8

Microsoft.Interropt.Excel DLL を使用して Excel クラスを作成しています。すべての機能を終了しましたが、デストラクタにエラーがあります。すべての変更をファイルに保存し、すべてのソースをリリースしたいと考えています。私はデストラクタでそれらすべてをしたい。しかし、私のデストラクタでは、Excel.ApplicationClass、Workbook、および Worksheet オブジェクトが例外で満たされ、「基になる RCW から分離された COM オブジェクトは使用できません」というメッセージが表示されます。ワークブックまたはワークシート オブジェクトにアクセスできないため、何も保存できず、何も閉じられません。

Destructor でクラスのプライベート メンバーにアクセスできませんか?

4

3 に答える 3

16

.NET がデストラクタに最も近いものは、.NET がファイナライザと呼ぶものです。主な違いは、デストラクタは通常、決定論的なファイナライズ (たとえば、オブジェクトの参照カウントがゼロになったとき) を行うのに対し、.NET ファイナライザは、オブジェクトが参照されなくなった後の不確定な時間に呼び出されることです。これは、単純な参照カウントを使用するのではなく、ルート トレース手順を使用して .NET ガベージ コレクターによって処理されます。

これに関する最高の記事の 1 つは、ガベージ コレクション: Microsoft .NET Framework の自動メモリ管理です。特にファイナライザーの詳細については、MSDNの記事「 Finalize Methods and Destructors」を参照してください。

Destructor でクラスのプライベート メンバーにアクセスできませんか?

いいえ、安全に行うことはできません。

あなたの場合、オブジェクトがルートによって直接的または間接的に参照されなくなった場合、オブジェクトが参照する COM オブジェクト、つまり、プライベート フィールドによって参照されるオブジェクトもルートによって参照されないということです。また。(オブジェクトのフィールドによって参照されても、これらの COM オブジェクトは存続しませ。これは、オブジェクトがルートによって参照されなくなったり、ルートからトレースされなくなったりするためです。したがって、COM オブジェクトはルートからもトレースされません。) したがって、オブジェクトとそれが参照するすべての COM オブジェクトは、すべて同時にガベージ コレクションの準備ができています。しばらくすると、ガベージ コレクターはオブジェクトをクリーンアップし、そのファイナライザーを呼び出します。これは、それぞれが実際にはランタイム呼び出し可能ラッパー (RCW)である COM オブジェクトに対しても行われます。.

問題は、これらのオブジェクトがガベージ コレクションされるタイミングが不確実であるだけでなく、ファイナライザーが呼び出される順序も非決定的であることです。この場合、Runtime Callable Wrapper には、 Marshal.ReleaseComObject自体を呼び出すファイナライザーもあり、この COM オブジェクトを解放できるように、フェンスの COM 側で参照カウントをデクリメントします。ただし、ファイナライザーが呼び出される順序は不明であるため、オブジェクトが参照する COM オブジェクトのファイナライザーが、オブジェクトのファイナライザーより前に起動する可能性が非常に高くなります。したがって、ファイナライザー内のコード動作することもありますが、ほとんどの場合、オブジェクトが参照する 1 つ以上のランタイム呼び出し可能ラッパーは、ファイナライザーが既に呼び出されており、ファイナライザーがそのコードを実行する前に、基になる COM オブジェクトが解放されます。

つまり、一般的にファイナライザーの使用を避ける必要があり、ファイナライザー内から参照型にアクセスしないでください。これらの参照型は既にファイナライズされている可能性があるためです。

あなたの状況を改善するために、2 つの異なる可能性を検討します。

  1. COM オブジェクトを作成した同じメソッド内で破棄します。これについては、ここここでいくつかの議論があります。

  2. 非決定論的なファイナライザーに頼るのではなく、 IDisposable インターフェイスを使用して、オブジェクトの決定論的な破棄を有効にします。

IDisposable パターンの実装方法に関する記事については、次を参照してください。

-- マイク

于 2010-01-18T21:46:16.973 に答える
1

コーディングが間違っているかどうかはわかりません。ここの例に従ってみました。IDisposable パターンを利用すると、ワークブック イベントを処理する必要がない限り、すべてが機能することがわかりました。

私のシナリオでは、ユーザーはアプリを閉じる前にワークブックを閉じることができます。Excel オブジェクトの WithEvents を宣言し、要件を満たすように WorkbookBeforeClose ハンドラーをコーディングしました。

このシナリオでは、アプリを閉じようとすると、"基になる RCW から分離された COM オブジェクトは使用できません" というエラーが表示されます (既に Excel を閉じています)。Dispose(False) を呼び出すと、Finalize でエラーが発生しています。

イベントで宣言された Excel オブジェクトをそのままにし、ハンドラーをコーディングしないと、問題は解決します。

Dispose では、Workbooks.Close と Quit のエラーを飲み込む必要がありました。これは、エラーの原因となったステートメントであるためです。

于 2010-02-02T22:11:17.433 に答える
0

いいえ、デストラクタ内の管理対象オブジェクトにアクセスしないでください。これにはCOMRCWが含まれます。

代わりに、標準のIDisposableパターンを実装し、使い捨ての管理対象オブジェクトと同じように、Dispose(bool)メソッドでCOMオブジェクトを解放します。

于 2010-01-18T15:20:03.803 に答える