2012-04-05 21 views
11

私はこの問題を思いつきました。質問:なぜfunc2が呼び出されますか? ああ、もう1つ。私は代理人に関数を追加すると言う。この関数では別の代理人を呼び出しますが、この関数がこの代理人を呼び出す前に最初の代理人に追加された関数がすべて呼び出されるようにしたいのですが、クリーンな解決策があります(getInvocationListに本当に関心がない)。 ありがとうございます、あなたは最高です。C#デリゲートは正常に動作しませんか?

class Program 
{ 
    delegate void voidEvent(); 
    voidEvent test; 

    private void func1() 
    { 
     Console.Write("func1"); 
     test -= func2; 
    } 

    private void func2() 
    { 
     Console.WriteLine("func2"); 
    } 

    static void Main(string[] args) 
    { 
     Program p = new Program(); 
     p.test += p.func1; 
     p.test += p.func2; 
     p.test(); 
    } 
} 

答えて

21

デリゲート(+ =または - =)を変更するたびに、呼び出しリストのコピー全体(呼び出されるメソッド)が効果的に作成されます。

p.test();を呼び出すと、の時点で、呼び出しリストのすべてのデリゲートが呼び出されます。これらのハンドラの1つをこの内部で変更すると、次の呼び出しで変更されますが、現在実行中の呼び出しは変更されません。

+3

+1。はい。このため、 'var func = p.test; if(func!= null){func(); } '何もロックせずにマルチスレッドのシナリオで。 'func'は' p.test'のコピーであり、 'p.test'に対する変更は気にしないからです。 –

+0

しかし、私はtest- = func2を呼び出してgetinvocationlistを呼び出すと、func2がリストにないことが分かります。だから、あなたは、すべての代議員が現在呼び出されている(そして到達可能でない)リストと、次回呼び出されるリストの2つのリストを持っていると言っていますか? – Yamcha

+0

@ user1316459、実際には2つのリストはありません。しかし、あなたがフィールドからデリゲートを呼び出すとき、あなたは効果的に何かを言う:「現場*の価値を今すぐ​​取ってからそれを呼び出す」。つまり、 'test'自体ではなく' test'の値のコピーを呼び出すことになります。 – svick

8

リードはもちろん正しいです。それについて考えるもう一つの方法があります。

class Number 
{ 
    public static Number test; 
    private int x; 
    public Number(int x) { this.x = x; } 
    public Number AddOne() 
    { 
     return new Number(x + 1); 
    } 
    public void DoIt() 
    { 
     Console.WriteLine(x); 
     test = test.AddOne(); 
     Console.WriteLine(x); 
    } 
    public static void Main() 
    { 
     test = new Number(1); 
     test.DoIt(); 
    } 
} 

1,1,1,2,1のいずれかを印刷しますか?どうして?

あなたは

 Console.WriteLine(test.x); 
     test = test.AddOne(); 
     Console.WriteLine(test.x); 

を意味するものではありません

test.DoIt(); 

を言うときには1、1を印刷する必要があります!むしろ、それはドイトでthisの値を変更しませんtestの値を変更する

Number temporary = test; 
Console.WriteLine(temporary.x); 
test = test.AddOne(); 
Console.WriteLine(temporary.x); 

を意味します。

あなたはまったく同じことをしています。 testの値を変更しても、呼び出す関数のリストは変更されません。呼び出される関数の特定のリストを要求し、そのリストは呼び出されます。途中で変更することはありません。方法の呼び出しの途中でthisの意味を変更する以上のことはありません。

+1

'Number'の定義に' x'フィールドがないようです。 – kvb

関連する問題