5

これら2つの実装に違いはありますか?

1:

public class SMSManager : ManagerBase
{
    private EventHandler<SheetButtonClickEventArgs> _buttonClickevent; 

    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) :
        base(smsDataBlock)
    {
        _buttonClickevent = new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);
        SheetEvents.ButtonClick += _buttonClickevent;

    }

    public override void Dispose()
    {
        base.Dispose();
        if (_buttonClickevent != null)
        SheetEvents.ButtonClick -= _buttonClickevent;
    }
}

2:

public class SMSManager : ManagerBase
{
    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) :
        base(smsDataBlock)
    {
        SheetEvents.ButtonClick += new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);   
    }

    public override void Dispose()
    {
        base.Dispose();
        SheetEvents.ButtonClick -= new EventHandler<SheetButtonClickEventArgs>(OnButtonClick);
    }
}

メモリリークに関しては、最初のものの方が2番目のものよりも正しいようです。しかし、それは本当に正しいのでしょうか?

4

1 に答える 1

5

その長短は、2番目のコードが正しく安全であるということです(ハンドラーが登録されていない場合でも)。

このサンプルアプリを検討してください。

namespace ConsoleApplication61
{
    class Program
    {
        static void Main(string[] args)
        {
            var f = new Foo();
            f.MyEvent += new EventHandler(Handler);
            f.Trigger();
            f.MyEvent -= new EventHandler(Handler);
            f.Trigger();
            Console.Read();
        }

        static void Handler(object sender, EventArgs e)
        {
            Console.WriteLine("handled");
        }
    }

    class Foo
    {
        public event EventHandler MyEvent;
        public void Trigger()
        {
            if (MyEvent != null)
                MyEvent(null, null);
        }
    }
}

このサンプルは、「処理済み」を1回印刷します。

したがって、あなたの例では、それらは機能的に同じであり、両方とも必要に応じて機能します。追加されていないハンドラーを削除することも安全なアクションです。削除するものが何も見つからず、何もしません。

コメントで提供されているように、マークの答えはより詳細になります:

デリゲートの新しいインスタンスでイベントの登録を解除します


匿名メソッドを使用するイベントハンドラー

ラムダ式の形式のイベントハンドラーは、インスタンスとメソッドのシグネチャに基づいて一意性を強制することが保証されていないことに注意してください。匿名メソッドのサブスクライブを解除する必要がある場合は、それをメソッドに昇格させるか、後で使用するために匿名メソッドへの参照を保持する必要があります。

Func<object, EventArgs> meth = (s, e) => DoSomething();

myEvent += meth;
myEvent -= meth;

Jon Skeetはこれに答えて詳細に説明し、おそらく私よりもうまくやってくれます:-)

ラムダイベントハンドラーを削除する方法


わずかなリファクタリング

私は次のようにリファクタリングします:

public class SMSManager : ManagerBase
{
    public SMSManager(DataBlock smsDataBlock, DataBlock telephonesDataBlock) 
        : base(smsDataBlock)
    {
        SheetEvents.ButtonClick += OnButtonClick;   
    }

    public override void Dispose()
    {
        SheetEvents.ButtonClick -= OnButtonClick;
        base.Dispose();
    }
}
于 2012-05-22T15:14:23.220 に答える