DOBON.NETプログラミング道掲示板

■34701 / 親記事)  エクセルのデータを配列に読込んだ時の配列要素番号について
  
□投稿者/ 雛鳥 一般人(1回)-(2021/04/27(Tue) 14:15:54)
  • アイコン環境/言語:[Win10 VS2019 .Net Flamework 4.7.2] 
    分類:[.NET] 

    お世話になります。

    ExcelのデータをOjbect型の二次元配列に読み込んだ際、
    ウォッチで取得したデータを確認すると
    配列の要素番号が1から始まっています。

    なぜ0始まりではなく、1始まりなのでしょうか?
    ご存知の方がいらっしゃいましたら、教えていただきたいです。

    以下、テストを行ったソースです。

    Private Sub test()
    Dim xlApp As New Microsoft.Office.Interop.Excel.Application
    Dim xlBooks As Excel.Workbooks
    Dim xlBook As Excel.Workbook
    Dim xlStData As Excel.Worksheet
    Dim xlRange As Range

    Dim excelData(,) As Object
    Dim filePath As String = "読み込むエクセルのファイルパス"

    'ファイルオープン
    xlBooks = xlApp.Workbooks
    xlBook = xlBooks.Open(filePath)
    xlStData = xlBook.Worksheets(1)

    'Excelデータを取得する
    xlRange = xlStData.Range("A1", "D6")
    excelData = CType(xlRange.Value, Object(,))

    'ファイルクローズ
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlStData)
    xlBook.Close(False)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBooks)
    xlApp.Quit()
    xlApp.DisplayAlerts = True
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)

    GC.Collect()
    End Sub
マルチポストを報告
違反を報告
引用返信 削除キー/
■34702 / ResNo.1)  Re[1]: エクセルのデータを配列に読込んだ時の配列要素番号について
□投稿者/ 魔界の仮面弁士 大御所(1330回)-(2021/04/28(Wed) 04:30:18)
  • アイコンNo34701に返信(雛鳥さんの記事)
    > なぜ0始まりではなく、1始まりなのでしょうか?

    Excel 側の仕様です。

    たとえば xlBook.Worksheets(1) が 1 ベースなのは、既定のシート名が
    Sheet1 から始まるので、あえて 0 ベースにしていないのだと想像されます。

    また、複数範囲を含む Range オブジェクトの Value プロパティは、
    行番号や列番号は 1 から始まるという事情もあり、伝統的に
    1 ベースの配列を返すようになっているのでしょう。

    なお、Property の Get 時には 1 ベースの配列が返されるだけであり、
    Property の Let 時には、1 ベース以外であっても構いません。


    ところで、ちょっと気になったのが解放処理。
    ReleaseComObject によって、COM の参照カウントを減ずるまでは良いですが、
    そのあとで GC.Collect() を使うのであれば、今のコードは逆効果になる可能性があります。

    参照が解放されていない状態で GC.Collect が呼ばれても、そのオブジェクトは解放されませんので、
    確実に回収させたいのであれば、ReleaseComObject の後で
     xlBook = Nothing
    などの参照を解放しておいてください。
    その後で、GC.WaitForPendingFinalizers() と GC.Collect() を呼ぶようにします。
    ※あるいは、変数がスコープ外になってからガベージコレクトを呼ぶようにする

    https://social.msdn.microsoft.com/Forums/ja-JP/5deec897-a897-404b-a610-f7d894fde1b3/office?forum=officesupportteamja
    https://social.msdn.microsoft.com/Forums/ja-JP/0d9c6273-bade-4f6a-a0de-5adb748d15eb/office?forum=officesupportteamja


    ガベージコレクトが行われた場合、その時点で参照中だったオブジェクトに対しては
    ジェネレーション昇格が発生します。本来は、ジェネレーション 0 がいっぱいになった時点で
    自動的に回収処理が走るのですが、無計画に GC.Collect してしまうと、Gen 0 から削除されるどころか
    むしろ Gen 1 に移動してしまい、自動起動されるガベージコレクトで回収されにくくなります。
    https://docs.microsoft.com/ja-jp/dotnet/standard/garbage-collection/fundamentals#generations
違反を報告
引用返信 削除キー/
■34703 / ResNo.2)  Re[2]: エクセルのデータを配列に読込んだ時の配列要素番号について
□投稿者/ 雛鳥 一般人(2回)-(2021/04/28(Wed) 14:25:29)
  • アイコンNo34702に返信(魔界の仮面弁士さんの記事)

    > Excel 側の仕様です。
    ずっと疑問で調べていたのですが、Excel 側の仕様なんですね…
    すっきりしました。
    教えてくださり、ありがとうございます!

    > ReleaseComObject によって、COM の参照カウントを減ずるまでは良いですが、
    > そのあとで GC.Collect() を使うのであれば、今のコードは逆効果になる可能性があります。
    解放処理へのご指摘もありがとうございます。
    ガベレージコレクトを行った際の一連の動作について 大変勉強不足でした…
    ご指摘いただいた通り、参照を解放してからGC.WaitForPendingFinalizers、GC.Collectを呼び出すよう修正しようと思います。

    参考サイト等も教えていただき、本当に助かりました。
    ありがとうございます!
解決み!
違反を報告
引用返信 削除キー/



スレッド内ページ移動 / << 0 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -