9

このワンライナーのマイナス面は、複数回使用するとDRY原則に違反するという事実以外にわかりますか? それは簡単に思えますが、他の人がそれを提案しているのを見たことがないという事実は、それにマイナス面があるかどうか疑問に思います.

このコードは、メソッドへのWeakReferenceを作成し、参照のターゲットを呼び出すイベント ハンドラーを登録します。

SomeEvent += (sender, e) => ((Action)(new WeakReference((Action)ProcessEvent)).Target)();

ありがとう、
ベン

4

2 に答える 2

13

そのパターンはあなたが期待するものではないと思います。メモリ リークを防ぐために、イベントが現在のオブジェクトへの参照を保持しないようにしようとしていますか? ラムダ式は、this評価するためにの値をキャプチャするためProcessEvent(インスタンス メソッドであると仮定ProcessEvent)、リークは引き続き発生します。このコードは、実行するのと同じSomeEvent += (sender, e) => ProcessEvent();です。

あなたはもっとこのようなことをしようとしているかもしれません(これもあなたが望むものではありません):

var reference = new WeakReference((Action)ProcessEvent);
SomeEvent += (sender, e) => ((Action)reference.Target)();

これで、ラムダ式は WeakReference をキャプチャするため、 への強い参照はありませんthis。残念ながら、ProcessEvent から作成されたデリゲートを参照しているものは他にないため、デリゲートthisがまだ生きている場合でも次の GC で削除されます。(これは、Target が null であることもチェックしません)。

次のようなことを試すことができます:

public EventHandler MakeWeakHandler(Action action, Action<EventHandler> remove)
{
    var reference = new WeakReference(action.Target);
    var method = action.Method;
    EventHandler handler = null;
    handler = delegate(object sender, EventArgs e)
    {
        var target = reference.Target;
        if (target != null)
        {
            method.Invoke(target, null);
        }
        else
        {
            remove(handler);
        }
    };
    return handler;
}

そして、次のように使用します。

SomeEvent += MakeWeakHandler(ProcessEvent, h => SomeEvent -= h);

これにより、ProcessEvent のレシーバーへの弱い参照が維持され、収集後にイベント ハンドラーがイベントから自動的に削除されます。これにより、イベントが定期的に発生する限り、メモリ リークが防止されます。

于 2010-07-15T21:55:36.480 に答える
0

あまり読みにくいです。また、ステップスルーしてデバッグする必要がある場合、これらのアクションのいずれかが失敗する可能性がありますが、その1行は失敗します。また、スタックトレースで参照されるのはその1行だけです。

通常、保守性のために、1行で多くのことを実行することは避けたいと考えています。

于 2010-07-15T21:29:37.630 に答える