1

次のように、の拡張メソッドを作成しようとしていますEventHandler

public static class MyExtensions
{
    public static void Add(this EventHandler handler, EventHandler next)
    {
        //Do something
    }
}

次のような私のイベントでは問題なく機能します。

public event EventHandler MyEvent

拡張機能を問題なく使用できます。

MyEvent.Add((x, y) => { /* do something */ });

しかし、それを TextBox の Click イベントに適用しようとすると、コンパイル エラーが発生します。

エラー CS0079:

イベント System.Windows.Forms.TextBoxBase.Click は、+=または-=

Click イベントは と何の違いもないように見えるのにMyEvent、なぜ制約があるのでしょうか?

4

2 に答える 2

4

Addメソッドが定義されている同じクラス内から呼び出された場合、MyEventおそらく問題なく動作します。

ただし、メソッドは、呼び出し元とは異なるクラスClickで定義されています。それがうまくいかない理由です。Add

.NET フレームワークでは、イベントを定義したクラスの外部でイベントを直接変更することは許可されていません。そうしないと、少し厄介なコードによって、任意のクラスのすべてのイベント ハンドラーが削除される可能性があります。

あなたが望むことをするのに役立つ、私が思いつくことができる最良の拡張方法は次のとおりです。

public static Action Add<TDelegate>(
    this TDelegate handler, 
    Action<TDelegate> addHandler, 
    Action<TDelegate> removeHandler)
{
    addHandler(handler);
    return () => removeHandler(handler);
} 

次のように使用できます。

var bar = new Bar();

EventHandler handler = (s, e) =>
{
    Console.WriteLine("MyEvent!");
};

var cleanup = handler.Add(h => bar.MyEvent +=h, h => bar.MyEvent -=h);
bar.Raise();
bar.Raise();
cleanup();

このcleanupアクションは、イベント ハンドラーが不要になったときに、イベント ハンドラーを削除するために使用されます。

簡単にするために、必要な null チェック コードはすべて省略しました。それらを適切な場所に配置する必要があります。

于 2012-10-07T11:53:57.420 に答える
1

両者には違いがあります。簡単な例でそれを示すことができます:

private EventHandler foodel;
public event EventHandler foo {
    add { foodel += value; }
    remove { foodel -= value; }
}
public event EventHandler bar;

...
foo.Add((s, e) => { });   // CS0079
bar.Add((s, e) => { });   // No error

アクセサーを削除すると、コードがきれいにコンパイルされます。

あなたは意図せずにコンパイラのバグを利用している、と言いたいところです。アクセサーなしで宣言されたイベントでの拡張メソッドの使用も拒否する必要がありました。Microsoft がバグを修正する可能性は非常に低く、これはあまりにも長い間出回っています。ただし、最善の回避策は、拡張メソッドを削除することです。

于 2012-10-07T12:56:36.533 に答える