コード レビューで、イベント ハンドラーの登録を解除するために、この (簡略化された) コード フラグメントに出くわしました。
Fire -= new MyDelegate(OnFire);
これまでに登録されたことのない新しいデリゲートが作成されるため、これはイベント ハンドラーの登録を解除しないと考えました。しかし、MSDN を検索すると、このイディオムを使用するコード サンプルがいくつか見つかりました。
だから私は実験を始めました:
internal class Program
{
public delegate void MyDelegate(string msg);
public static event MyDelegate Fire;
private static void Main(string[] args)
{
Fire += new MyDelegate(OnFire);
Fire += new MyDelegate(OnFire);
Fire("Hello 1");
Fire -= new MyDelegate(OnFire);
Fire("Hello 2");
Fire -= new MyDelegate(OnFire);
Fire("Hello 3");
}
private static void OnFire(string msg)
{
Console.WriteLine("OnFire: {0}", msg);
}
}
驚いたことに、次のことが起こりました。
Fire("Hello 1");
予想どおり、2 つのメッセージが生成されました。Fire("Hello 2");
1つのメッセージを作成しました!これにより、デリゲートの
登録解除が機能することが確信できました。new
Fire("Hello 3");
を投げたNullReferenceException
。
コードをデバッグすると、イベントの登録を解除した後であることFire
が示されました。null
イベント ハンドラーとデリゲートについては、コンパイラが舞台裏で多くのコードを生成することを知っています。しかし、なぜ私の推論が間違っているのか、まだ理解できません。
私は何が欠けていますか?
Fire
追加の質問: イベントが登録されていないという事実から、null
イベントが発生するすべての場所でチェックnull
が必要であると結論付けます。