これら 2 つのコード スニペットは同じだと思います。ここでは、強/弱参照に問題はありません。
バックグラウンド
まず第一に、Interop.ComObjectWrapper
CLR イベント (つまり、イベント ハンドラーをデリゲートに格納するイベント) を提供する場合ComObjectWrapper
、オブジェクトへの強力な参照を確実に取得します。
Target
すべてのデリゲートには、型object
と特定のメソッドへのメソッド ポインターの2 つの部分が含まれます。Target
コールバックがnull
静的メソッドを指している場合。
Target
タイプWeakReferenceのデリゲートを持つことは不可能です。いわゆる弱いイベント パターンがありますが、プレーン デリゲートの代わりにEventManagerの上に実装されます。
イベント ハンドラをフィールドに格納しても役に立ちません。パート1
内部イベントの実装とは、イベントをサブスクライブした後に次のことを意味します。
comObject.SomeEvent += EventCallback;
comObject
object は暗黙的にオブジェクトへの強い参照を保持しSomeClass
ます。これは、使用しているサブスクライブ手法の種類や、ComObject が COM オブジェクト ラッパーであるかどうかに関係なく当てはまります。
イベントをサブスクライブすると、有効期間に関して 2 つのオブジェクト間に暗黙的な依存関係が追加されます。そのため、.NET の世界で最も一般的なメモリ リークは、長寿命オブジェクトのイベントへのサブスクライブによって引き起こされます。イベント サブスクライバーは、イベント ホルダーがアプリケーションでアクセス可能になるまで終了しません。
イベント ハンドラをフィールドに格納しても役に立ちません。パート2
しかし、私の仮定が正しくなくComObjectWrapper
、弱いイベント パターンの概念を提供する場合、イベント ハンドラーをフィールドに保存しても何の役にも立ちません。
イベントキーワードの意味を要約しましょう:
private event ComEventHandler comEventHandler;
...
comEventHandler = new ComEventHandler(EventCallback);
コールバックを現在のフィールドに保存しても (基本的に、プライベート イベントを単純なデリゲート フィールドとして扱うことができます)、既存の動作は変わりません。
SomeClass
デリゲートは、Target オブジェクト (オブジェクト) とメソッド (オブジェクト)への参照を格納する単純なオブジェクトであることは既にわかっていますpublic void EventCallBack()
。これは、フィールドに追加のデリゲートを格納するとSomeClass
、 自体からへの追加の参照が追加されることを意味しSomeClass
ます。
基本的に、フィールドにイベント ハンドラーを格納することは、追加の参照を SomeClass に格納することと意味的に同等です。
プライベート SomeClass someClass;
public SomeClaas() { // これは基本的にデリゲートを // comEventHandler フィールドに格納するのと同じです someClass = this; }
に強い参照を格納してSomeClass
も、現在のオブジェクトの有効期間は延長されません。これは、イベント ハンドラーを格納するオブジェクトComObjectWrapper
への強い参照を保持しない場合、 SomeClass の有効期間を延長せず、ガベージ コレクションを妨げないことを意味します。SomeClass
comEventHandler
SomeClass
結論
イベント ハンドラーをプライベート フィールドに格納しても、オブジェクトの有効期間は延長されず、ガベージ コレクションも妨げられません。
そのため、オブジェクトの有効期間に関して、次のコード スニペットに違いはありません。
// GOOD!
comObject.SomeEvent += new ComEventHandler(EventCallback);
// EVEN BETTER!
comObject.SomeEvent += EventCallback;
// NOT GOOD, BECAUSE WAN'T HELP!
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler