1

COM オブジェクトでイベントを処理するために匿名メソッドを使用しています。プログラムが終了すると、監視していたすべてのリソースに対して最初の例外 (InvalidComObjectException) が発生するという点で、匿名メソッドで使用しているリソースが「正しく閉じられていない」ように見えます。これは大したことではないと思いますが、「正しい」とは感じません。

匿名メソッドの範囲外でキャプチャされた変数にアクセスする方法を理解することはできません(とにかく、できるはずはありません)。アプリケーションを終了する前にリソースを閉じる/破棄するにはどうすればよいですか?

編集: 簡単に読み直した後、ここで何をしているのかはっきりしないかもしれません。COM オブジェクトを使用するマネージ アプリケーションを作成しています。

さらに編集: ArcGIS Engineを使用して GIS データを操作しています。この特定のケースでは、ILayerEvents_Event の VisibilityChanged イベントを使用して、GIS レイヤーがいつ表示または非表示になるかを監視しています。イベントはブール値 (可視または不可視) のみを渡し、レイヤー名は渡さないため、可視状態の変更を作成するには、レイヤーごとにメソッドを作成する必要があります。私は動的レイヤーを扱っているので、何らかの形でこれを動的に行う方法が必要だったので、匿名メソッドが必要でした。

anonymoua メソッド内に、(ILayer コンテキスト内の) 外側のループから ILayerEvents_Event を取得する ILayer 変数があるため、どのレイヤーを使用しているかがわかります。私が立ち往生しているのはこの時点です。機能は機能し、アプリケーションを終了するまですべてが壮大で、20 以上の参照がそこにぶら下がっていて、行く場所がなく、例外があります。

ユーザーが最後にレイヤーを非表示/表示する時期がわからないため、最後に物事を無効にする方法はありません。何も害がないように見えるので、そのままにしておくことができると思います(または、匿名メソッドよりもこれを行うためのより良い方法があるかもしれません)。何かが足りないと思うだけです。

4

3 に答える 3

1

説明した方法からこれを知ることはまったく不可能ですが、COM オブジェクトで公開されたイベントのイベント ハンドラーとしてこれらのオブジェクトのメソッドが登録されているため、C# オブジェクトへの参照を保持している COM オブジェクトがある可能性があります。 COM オブジェクトが使用されなくなると、ファイナライズされます。COM オブジェクトが「アパートメント」ベースであると仮定すると、これは、メッセージがファイナライザー スレッドから COM オブジェクトを作成したスレッドの Windows メッセージ キューにポストされ、COM オブジェクトで Release を呼び出すように要求することを意味します。その時点で、COM オブジェクトは、参加しているイベント ハンドラーを実装する C# オブジェクトで Release を呼び出す可能性があります。これはおそらく、アプリケーションの最後のマネージ コードの実行が終了したときに発生しているため、CLR は自身をアンロードしようとしています。シャットダウン中に、CLR は、オブジェクトの参照カウントがゼロになる前にオブジェクトを収集または無効な状態にすることで、可能性のある参照カウント リークに対処する必要がある可能性があります。したがって、これは(純粋な推測で)あなたが見ているものを説明するかもしれません.

その場合は、自分で選択した時点で COM オブジェクトをシャットダウンする必要があります。Marshal.ReleaseComObject解決策は、アプリケーションの通常のシャットダウンの一部として、COM オブジェクトでゼロが返されるまでループで呼び出すことです。

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject(VS.71).aspx

更新された質問に基づく更新:

これで、匿名メソッド クロージャによって参照される COM オブジェクトがいくつかできました。これらの COM オブジェクトに発生する唯一のことは、それらに対して Release が呼び出されることです。それが問題の原因である場合は、それらが既に無効な状態にあることが原因である可能性が最も高いです。

したがって、COM オブジェクトへの参照を保持する一連の匿名メソッド クロージャを作成する場合は、それらの COM オブジェクトも別のリストに追加することをお勧めします。Marshal.ReleaseComObjectこれにより、このシステム全体を破棄するときにそれらを呼び出すことができます。

于 2009-05-27T23:04:59.553 に答える
1

本当に必要な場合は、アプリケーションの終了イベントにフックする必要があります。とはいえ、それ以上にうまくやればよかったと思っています。

匿名メソッドを何に使用していますか? 最後にいつ使用されたかを調べて、COM オブジェクトを破棄できますか? 匿名メソッドが COM オブジェクト取得し、それらをすべて同じブロック内で破棄できるようにすることはできますか?

ご覧のとおり、悪魔は細部に宿ります :)

于 2009-05-27T22:43:36.867 に答える