35

C#言語設計についての小さな質問:))

私がこのようなインターフェースを持っていた場合:

interface IFoo {
  int Value { get; set; }
}

C#3.0の自動実装プロパティを使用して、このようなインターフェイスを明示的に実装することができます。

sealed class Foo : IFoo {
  int IFoo.Value { get; set; }
}

しかし、インターフェイスにイベントがあった場合:

interface IFoo {
  event EventHandler Event;
}

そして、フィールドのようなイベントを使用して明示的に実装しようとしています。

sealed class Foo : IFoo {
  event EventHandler IFoo.Event;
}

次のコンパイラエラーが発生します。

error CS0071: An explicit interface implementation of an event must use event accessor syntax

フィールドのようなイベントは、自動実装されたプロパティのある種の二元論だと思います。

だから私の質問は:そのような制限が行われる設計上の理由は何ですか?

4

4 に答える 4

32

興味深い質問です。言語ノートのアーカイブを少し調べてみたところ、この決定は1999年10月13日に行われたことがわかりましたが、ノートは決定を正当化するものではありません。

頭のてっぺんから、フィールドのような明示的に実装されたイベントを作成できなかった理論的または実践的な理由はわかりません。また、私たちが特に必要とする理由もわかりません。これは未知の謎の1つであり続ける必要があるかもしれません。

于 2010-02-15T19:43:33.917 に答える
29

クラスの他のメンバーから明示的なインターフェイス実装を呼び出すことができないという事実に関係しているのではないかと思います。

public interface I
{
    void DoIt();
}

public class C : I
{
    public C()
    {
        DoIt(); // error CS0103: The name 'DoIt' does not exist in the current context
    }

    void I.DoIt() { }
}

最初にインターフェースにアップキャストすることでメソッドを呼び出すことができることに注意してください((I)this).DoIt();。少し醜いですが、動作します。

ControlFlow(OP)が提案するようにイベントを明示的に実装できるとしたら、実際にどのようにイベントを発生させますか?検討:

public interface I
{
    event EventHandler SomethingHappened;
}

public class C : I
{
    public void OnSomethingHappened()
    {
        // Same problem as above
        SomethingHappened(this, EventArgs.Empty);
    }

    event EventHandler I.SomethingHappened;
}

ここでは、最初にインターフェイスにアップキャストしてイベントを発生させることもできません。これは、イベントは実装クラス内からのみ発生するためです。したがって、明示的に実装されたイベントにアクセサ構文を要求することは完全に理にかなっているようです。

于 2012-02-07T15:28:48.980 に答える
23

インターフェイスで宣言されたイベントを明示的に実装する場合は、コンパイラによって通常提供される追加および削除イベントアクセサを手動で提供する必要があります。アクセサコードは、インターフェイスイベントをクラス内の別のイベントまたは独自のデリゲートタイプに接続できます。

たとえば、これによりエラーCS0071がトリガーされます。

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

class Test : Itest
{
    event MyEvent ITest.Clicked;  // CS0071
    public static void Main() { }
}

正しい方法は次のとおりです。

public delegate void MyEvent(object sender);

interface ITest
{
    event MyEvent Clicked;
}

class Test : Itest
{
    private MyEvent clicked;

    event MyEvent Itest.Clicked
    {
        add
        {
            clicked += value;
        }

        remove
        {
            clicked -= value;
        }
    }

    public static void Main() { }
}

コンパイラエラーCS0071を参照してください

于 2010-02-15T20:04:43.977 に答える
1

これは実際には私自身の独創的な考えではありません。

しかし、私はこれに対応するかもしれないと思いました:

「頭のてっぺんから、フィールドのような明示的に実装されたイベントを実行できなかった理論的または実践的な理由はわかりません。また、特に必要な理由もわかりません。これは謎の1つであり続ける必要があるかもしれません。未知の」-エリック・リペット


プログラマーによるC#入門、第2版の第23章で、EricGunnersonは次のように書いています。

「ボタンがクリックされたときに別のクラスも呼び出されるようにしたい場合は、次のように+=演算子を使用できます。

button.Click + = new Button.ClickHandler(OtherMethodToCall);

残念ながら、他のクラスが注意を怠った場合、次のことを行う可能性があります。

button.Click = new Button.ClickHandler(OtherMethodToCall);

ButtonHandlerがフック解除され、新しいメソッドのみが呼び出されることを意味するため、これは悪いことです。」

..。

「必要なのは、デリゲートフィールドを保護して、+=と-=を使用してのみアクセスできるようにする方法です。」


彼は次の数ページに進み、この動作を実装するためのadd()メソッドとremove()メソッドの組み込みについてコメントします。これらのメソッドに直接書き込むことができることと、不要なデリゲート参照のストレージ割り当ての結果。

さらに追加しますが、作者を尊敬しすぎて、彼の許可なしにそうすることはできません。私はこの本のコピーを見つけることをお勧めします、そして一般的にエリック・ガンナーソンによるものをお勧めします(ブログなど...)

とにかく、これがトピックに関連していることを願っています。もしそうなら、それがこの「未知の謎」に光を当てることを願っていますか?(私はこの章を読み、カスタムオブジェクトからカスタムコレクションを作成する際のイベントハンドラロジックの考慮事項についての洞察を得るためにStack Overflowを検索していました)-この特定の主題に関する特定の権限を主張していないため、これについてのみ言及します。私は自分自身「悟り」を求めている学生に過ぎません:-)

于 2010-05-06T07:34:48.650 に答える