2012-04-05 2 views
11

저는 C#에 다소 새로운 것이므로이 문제를 생각해 냈습니다. 질문 : func2를 호출하는 이유는 무엇입니까? 오, 그리고 한가지 더. 대리자에 함수를 추가한다고 해봅시다. 이 함수에서는 다른 대리자를 호출하지만이 함수가이 대리자를 호출하기 전에 첫 번째 대리자에 추가 된 다른 모든 함수가 호출되도록하고 싶습니다. 깨끗한 솔루션 (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();을 호출하면 해당 시점에의 호출 목록 에있는 모든 대리인을 호출하게됩니다. 이러한 핸들러 중 하나를 변경하면 다음 호출을 위해이 핸들러가 변경되지만 현재 실행중인 호출은 변경되지 않습니다.

+3

+1. 예. 이것이 왜'var func = p.test; if (func! = null) {func(); }'아무것도 잠그지 않고 다중 쓰레딩 시나리오에서. 왜냐하면'func'는'p.test'의 복사본이기 때문에'p.test'에 대한 변경은 신경 쓰지 않습니다. –

+0

하지만 test- = func2를 호출하고 getinvocationlist를 호출하면 func2가 더 이상 목록에 없음을 알 수 있습니다. 따라서 모든 대표는 두 개의 목록을 가지고 있다고 말하면서 현재 호출 된 (그리고 도달 할 수없는) 목록과 다음 번에 호출 할 목록이 있습니다. – Yamcha

+0

@ user1316459, 실제로 두 개의 목록이 없습니다. 그러나 소송에서 대표를 파견 할 때, 당신은 효과적으로 "현장 *의 가치를 취하여 그 다음에 그것을 호출하십시오."같은 말을 효과적으로합니다. 즉,'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? 왜?

그것은 당신이

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

을 의미하지는 않습니다

test.DoIt(); 

을 말할 때, (1) 1. 인쇄해야합니다! 오히려, 그 DOIT에 this의 값을 변경하지 않는다 test의 값을 변경

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

의미한다.

정확히 똑같은 일을하고 있습니다. test 값을 변경해도 호출중인 함수 목록은 변경되지 않습니다. 특정 함수 목록을 호출하도록 요청했고 목록이 호출됩니다.. 당신은 중도 변경을하지 않고, 메서드 호출을 통해 this의 의미를 변경하는 것 이상의 효과가 있습니다.

+1

'Number'의 정의에서'x' 필드가 누락 된 것 같습니다. – kvb

관련 문제