0

私はこの単純なイベントを持っています:

public class ClassA
{
    public event Func<string, int> Ev;
    public int Do(string l)
    {
        return Ev(l);
    }
}

そして2つの方法:

  static int Display(string k)
        {
            return k.Length;
        }

  static int Display_2(string k)
        {
            return k.Length*10;
        }

このイベントを登録しています:

 ClassA a = new ClassA();
 a.Ev += Display;
 a.Ev += Display_2;

今、私は実行しています:

   Console.WriteLine(a.Do("aaa")); 

出力 :

ここに画像の説明を入力

何 ???

  • 彼は呼び出しリストに2つのメソッドを持っています! それらを実行しましたが、最後の登録からの結果のみを表示するのはなぜですか?

  • hasの結果はどこ"3"に行ったのですか? (最初の呼び出し) ? (両方のdisplay+display_2が実行されましたが...console.write結果を繰り返し処理するとは思っていませんでしたが、どちらを表示するかを彼が決定することも期待していませんでした。 )

編集 :

ここに画像の説明を入力

4

4 に答える 4

7

ここには 3 つの側面があります。

  1. イベントの実装
  2. デリゲートの組み合わせの動作
  3. 呼び出しリストに複数のエントリがあるデリゲートを呼び出す動作

ポイント 1 については、フィールドのようなイベントがあります。C# 4 仕様のセクション 10.8.1 に例が示され、次のように述べられています。

Buttonクラスの宣言の外では、次のように、 and演算子Clickの左辺でのみメンバーを使用できます。+=-=

b.Click += new EventHandler(...);

イベントの呼び出しリストにデリゲートを追加しますClick

(強調鉱山)。この仕様では、フィールドのようなイベントがデリゲート フィールドを作成することも明確にしています。デリゲート フィールドは、呼び出しのためにクラス内から使用されます。

より一般的に (ポイント 2)、C# 4 仕様のセクション 7.8.4 では、+andを介したデリゲートの組み合わせについて説明してい+=ます。

デリゲートの組み合わせ。すべてのデリゲート型は、次の事前定義された演算子を暗黙的に提供します。ここDで、 はデリゲート型です。

D operator +(D x, D y)

二項+演算子は、両方のオペランドがデリゲート型の場合にデリゲート結合を実行しますDx[... orが null のビットをスキップする...] それ以外の場合、操作の結果は、呼び出されたときに最初のオペランドを呼び出し、次に 2 番目のオペランドを呼び出すy新しいデリゲートです。

(繰り返しますが、私のものを強調してください。)

最後に、ポイント 3 - イベントの呼び出しと戻り値。C# 仕様のセクション 15.4 には次のように記載されています。

デリゲートの呼び出しに出力パラメーターまたは戻り値が含まれている場合、それらの最終的な値は、リスト内の最後のデリゲートの呼び出しから取得されます。

より一般的には、イベントの実装に依存します。「通常の」デリ​​ゲートの組み合わせ/削除手順を使用するイベント実装を使用すると、すべてが保証されます。クレイジーなことをするカスタム実装を書き始めたら、それは別の問題です。

于 2012-12-07T09:31:30.877 に答える
4

マルチキャストの非voidデリゲートを呼び出すと、最後に実行されたハンドラーの値が返されます。

誰が最初か最後かを制御することはほとんどできません。使用するのはお粗末なシステムです。

これが、ほとんどのイベントとデリゲートが戻る理由voidです。

于 2012-12-06T16:51:13.073 に答える
4

原則として、イベントが値を返すことは意味がありません。

イベント ハンドラーから情報を取得する場合は、イベント ハンドラーが入力パラメーターを変更するか、イベントを発生させたオブジェクトの別のメソッドを呼び出して何か他のことを伝える方が理にかなっています。

イベントは論理的にイベント ハンドラーに情報を渡し、イベント ハンドラーから情報を取得する必要がないため、通常、これは発生しません。それは正直なところ、コードの臭いの兆候です。イベントは、誰かがサブスクライブしているかどうか、誰であるか、何をしているか、またはサブスクライバーがいるかどうかを気にするべきではありません。それらからの戻り値に依存すると、過度に緊密な結合が作成されます。

于 2012-12-06T16:49:09.807 に答える
3

イベントは、添付された順序で繰り返されます。戻り値を使用しているため、取得する値は最後に呼び出されたものです。

ただし、これはイベントの通常のパターンではありません。おそらく、もう少し次のようなものが必要です。

public class MyEventArgs : EventArgs
{
    public MyEventArgs()
    {
        Results = new List<int>();
    }
    public string InputString{get;set;}
    public List<int> Results{get;set;}
}
public event EventHandler<MyEventArgs> Ev
public int Do(string l)
{
    MyEventArgs e = new MyEventArgs();
    e.InputString = l;
    if(Ev != null) Ev(this, e);
    return e.Results.Sum();
}

その後

static int Display(object sender, MyEventArgs e)
        {
            return e.Results.Add(k.Length);
        }

  static int Display_2(object sender, MyEventArgs e)
        {
            return e.Results.Add(k.Length*10);
        }
于 2012-12-06T16:58:21.127 に答える