5

委任者:わかりました。でも、イベントに引っ越すと、よくわからないことがたくさんあります。私は本、MSDN、およびネットワークに関するいくつかの簡単な例を読みましたが、どちらも同じ構造を持っています。たとえば、次のリンクがあります:イベントの例

私は最初の例を取り上げます。著者は、C#イベントに関する最も簡単な例だと言っています。

これが彼のコードです:

public class Metronome
{
    public event TickHandler Tick;
    public EventArgs e = null;
    public delegate void TickHandler(Metronome m, EventArgs e);
    public void Start()
    {
        while (true)
        {
            System.Threading.Thread.Sleep(3000);
            if (Tick != null)
            {
                Tick(this, e);
            }
        }
    }
}

public class Listener
{
    public void Subscribe(Metronome m)
    {
        m.Tick += new Metronome.TickHandler(HeardIt);
    }
    private void HeardIt(Metronome m, EventArgs e)
    {
        System.Console.WriteLine("HEARD IT");
    }
}

class Test
{
    static void Main()
    {
        Metronome m = new Metronome();
        Listener l = new Listener();
        l.Subscribe(m);
        m.Start();
    }
}

次の行に注意してくださいpublic event TickHandler Tick。に変更してpublic TickHandler Tickも、プログラムは同じように実行されます。しかし、それは単なる委任であるため、私が理解している改行。

eventだから、私の質問は:行のキーワードの本当の目的は何ですか: public event TickHandler Tick。すべての例で常にこのように使用されるため、これは非常に重要ですが、その理由を説明することはできません。

ありがとう :)

4

7 に答える 7

9

デリゲートとイベントは関連する概念ですが、同じものではありません。「委任する」という用語は、2つの意味を持つ傾向があります(多くの場合、光沢があります)。

  • シングルメソッドインターフェイスに似たデリゲートタイプ。(大きな違いはありますが、それが妥当な出発点です。)
  • そのタイプのインスタンス。多くの場合、メソッドグループを介して作成され、デリゲートが「呼び出された」ときにメソッドが呼び出されます。

イベントはそのどちらでもありません。これは、タイプの一種のメンバーです。つまり、add / removeメソッドのペアであり、デリゲートを使用してイベントをサブスクライブまたはサブスクライブ解除します。を使用する場合は、addメソッドとremoveメソッドが使用されfoo.SomeEvent += handler;ますfoo.SomeEvent -= handler;

これは、プロパティが実際にget / setメソッドのペア(または2つのうちの1つ)である方法と非常によく似ています。

このようなフィールドのようなイベントを宣言すると、次のようになります。

public event TickHandler Tick;

コンパイラは、次のようなメンバーをクラスに追加します

private TickHandler tick;

public event TickHandler
{
    add { tick += value; }
    remove { tick -= value; }
}

それよりも少し複雑ですが、それが基本的な考え方です。これは、自動的に実装されたプロパティのように、イベントの単純な実装です。クラスの内部からはバッキングフィールドにアクセスできますが、クラスの外部では常にイベントを使用するだけになります。

個人的には、フィールドのようなイベントの宣言がデリゲートタイプのフィールドに非常によく似ているのは残念だと思います。これは、eventキーワード「変更」のように、一部の回答に誤解を招く(IMO)ステートメントが含まれることになります。「フィールド宣言-実際には、まったく異なるものを宣言していることを意味します。フィールドのようなイベントが自動的に実装されたプロパティのように見えたらもっと明確だったと思います。

// Not real C#, but I wish it were...
public event TickHandler Tick { add; remove; }

私はあなたが役に立つと思うかもしれないかなり詳細に入る記事全体を持っています。

于 2012-05-22T17:35:13.423 に答える
7

eventキーワードは基本的にあなたの操作を制限しますdelegate=演算子を使用して手動で割り当てることはできなくなりました。

イベントからデリゲートを1つずつ追加(使用+=)または削除(使用)することしかできません。-=これは、一部のサブスクライバーが他のサブスクリプションを「上書き」するのを防ぐために行われます。

したがって、次のことはできません。m.Tick = new Metronome.TickHandler(HeardIt)

于 2012-05-22T17:01:18.847 に答える
3

" event"は修飾子です。メリットは何ですか?

  1. インターフェイスでイベントを使用できます
  2. イベントを呼び出すことができるのは、それを宣言しているクラスのみです。
  3. イベントは、オーバーライドしてカスタム処理を実行できるアクセサを公開しaddますremove
  4. イベントは、割り当てられたメソッドの特定のシグニチャに制限されSomeMethod(object source, EventArgs args)、イベントに関する追加情報を提供します。
于 2012-05-22T17:08:29.890 に答える
1

正解です。eventキーワードの追加はほとんど冗長なようです。ただし、イベントであるフィールドと純粋なデリゲートに入力されるフィールドには重要な違いがあります。eventキーワードを使用するということは、包含オブジェクトの外部のオブジェクトはデリゲートをサブスクライブできますが、それを呼び出すことはできないことを意味します。eventキーワードを削除すると、外部オブジェクトはサブスクライブしてデリゲートを呼び出すことができます(可視性が許可されます)。

于 2012-05-22T17:02:54.110 に答える
1

プログラムにリスナーを追加するときは、デリゲートではなくイベントを追加します

コードを参照してくださいm.Tick+=

プロパティ(イベントタイプ)を要求している部分があり、それに+=を使用してリスナーを追加していることがわかります。これで、そのTickプロパティにTickHandlerタイプのみを追加できます。これをオーバーライドする場合は、TickHandlerと同じ形式の独自のタイプを作成する必要があります。

文字列またはintに追加する場合とよく似ています。

string stringTest = string.Empty;
stringTest += "this works";
stringTest += 4; //this doesn't though
int intTest = 0;
intTest += 1; //works because the type is the same
intTest += "This doesn't work";
Metronome m = new Metronome();
Metronome.TickHandler myTicker = new Metronome.TickHandler(function);
m.Tick += myTicker; //works because it is the right type
m.Tick += 4; //doesn't work... wrong type
m.Tick += "This doesnt work either"; //string type is not TickHandler type

それはそれをいくらかクリアしますか?

于 2012-05-22T17:07:17.930 に答える
1

私が知る限り、イベントは基本的にマルチキャストデリゲートですが、基本的な操作には異なるアクセスルールがあり、デリゲートとイベントが定義されているクラスの内外から実行できます。

操作は次のとおりです。

=演算子を使用して割り当てます

+=および-=演算子を使用して追加/削除

()演算子を使用して呼び出す

              Operation         | delegate   | event
              ------------------+------------+--------
Inside class  += / -=           | valid      | valid
              ------------------+------------+--------
Inside class  =                 | valid      | valid
              ------------------+------------+--------
Inside class  ()                | valid      | valid
              ------------------+------------+--------
Outside class  += / -=          | valid      | valid
              ------------------+------------+--------
Outside class  =                | valid      | not valid
              ------------------+------------+--------
Outside class  ()               | valid      | not valid

これにより、常に優れたOOPスタイルであるカプセル化が可能になります。:-)

于 2012-05-22T17:08:04.243 に答える
0

デリゲートとイベントの使用の主な違いは、イベントはサーバー(クラスの作成者を意味する)によってのみ発生させることができるということだと思います

ここでキーワードを削除すると、そうでない場合はでeventを上げることができます。m.Tick(sender,e)Listener

public class Listener
{
  public void Subscribe(Metronome m)
  {
    m.Tick += new Metronome.TickHandler(HeardIt);
  }

  private void RaisTick(object sender, EventArgs e)
  {
      m.Tick(sender,e);
  }
  private void HeardIt(Metronome m, EventArgs e)
  {
     System.Console.WriteLine("HEARD IT");
  }

}

于 2012-05-22T17:03:26.253 に答える