■No35250に返信(たこさんの記事) > Private _xlsApplication As Excel.Application = Nothing > Friend ReadOnly Property xlsApplication As Excel.Application > Get > Return _xlsApplication > End Get > End Property これではあまり意味が無いと思いますよ。結局のところ、 Friend ReadOnly xlsApplication As Excel.Application な読み取り専用フィールドと、さほど変わらないように見えます。
COM オブジェクトを直接公開してしまうと、ExcelEx の外部で ExEx1.xlsApplication.Workbooks.Add() などと書かれてしまえば、COM オブジェクトの解放漏れに繋がります。
IDisposable としてカプセル化するのであれば、Excel の COM オブジェクトは 外部からは直接操作できないようにして、すべてクラス内に隠蔽します。 戻り値と返すのも COM オブジェクトではなく、.NET のマネージオブジェクトにします。
> Option Strict Onをすると『Option Strict On では、遅延バインディングを使用できません。』といっぱい怒られます(^^ゞ 書き換えながら、御自身で正解に向かったところもあるようですが、一応ひとつひとつ見ていきましょうか。
> If Not check Then > _xlsWorkSheet = xlsApplication.Sheets.Add() この処理には、問題点が 2 つあります。
1 つは「.」による COM オブジェクトの連続呼び出しであり、 Sheets プロパティから返されるコレクションの解放が漏れています。
COM に対する For Each は、COM の IEnumVARIANT インターフェイスを通じて行われるため、 稀に、これが解放の妨げになることがあるためです。 https://learn.microsoft.com/ja-jp/windows/win32/api/oaidl/nn-oaidl-ienumvariant https://divakk.co.jp/aoyagi/csharp_tips_vssenum.html
なので For Each ループではなく、For ループを Count プロパティと共に使う方が安全です。 https://qiita.com/mima_ita/items/aa811423d8c4410eca71
> If Not check Then > _xlsWorkSheet = xlsApplication.Sheets.Add() '←ここでも怒られますが、『CType(xlsApplication.Excel.Sheets, Excel.Worksheet).Add()』としてみましたが、怒られたままです>< xlsApplication は Excel.Application 型ですよね。
そもそも「xlsApplication.Sheets(strSheetName)」の Sheets メンバーというモノは、 Property Sheets(n As String) As Object なプロパティでもなければ Function Sheets(n As String) As Object なメソッドでもありません。
その実態は ReadOnly Property Sheets() As Excel.Sheets という『引数の無いメンバー』です。
こうした「既定のプロパティ」によって、「『.』の連続」が見えにくくなる事象は 他の COM コレクション型に対しても発生します。たとえば Dim r As Excel.Range = Sheet1.Cells(1, 1) 'Cells プロパティの引数に 1,1 を渡しているように見えるが…? r.Value = 123 なども解放漏れ要因になるので NG ですね。
上記で解放漏れを防ぐには、 Dim r1 As Excel.Range = Sheet1.Cells '実は Cells プロパティは、「引数を持たない」仕様です Dim r2 As Excel.Range = r1(1, 1) 'そしてこれは、Range オブジェクトの .Item(1, 1) に相当します r2.Value = 123 MRComObject(r2) MRComObject(r1) などのような操作が求められます。
> For Each sh In xlsSheets > If CType(sh, Excel.Worksheet).Name = strSheetName Then > check = True > Exit For > End If > Next
For Each を For に置き換えるとこんな感じ。
Dim found As Boolean = False For n As Integer = 1 To xlsSheets.Count Dim ws = DirectCast(xlsSheets(n), Excel.Worksheet) Dim nm = ws.Name MRComObject(ws) If nm = strSheetName Then found = True Exit For End If Next