2008-10-23 9 views
7

이 코드가 어떻게 작동하는지 사용자가 알 수 있습니까? 코드에 삽입 된 주석을 확인하십시오 ...대리자를 통해 대체 가능한 메서드를 실행할 때 Invoke() 및 BeginInvoke()가 다르게 동작

여기에 정말 분명한 것을 놓치고 있습니까?

using System; 
namespace ConsoleApplication3 
{ 
    public class Program 
    { 
     static void Main(string[] args) 
     { 
      var c = new MyChild(); 
      c.X(); 
      Console.ReadLine(); 
     } 
    } 

    public class MyParent 
    { 
     public virtual void X() 
     { 
      Console.WriteLine("Executing MyParent"); 
     } 
    } 

    delegate void MyDelegate(); 

    public class MyChild : MyParent 
    { 
     public override void X() 
     { 
      Console.WriteLine("Executing MyChild"); 
      MyDelegate md = base.X; 

      // The following two calls look like they should behave the same, 
      // but they behave differently!  

      // Why does Invoke() call the base class as expected here... 
      md.Invoke(); 

      // ... and yet BeginInvoke() performs a recursive call within 
      // this child class and not call the base class? 
      md.BeginInvoke(CallBack, null); 
     } 

     public void CallBack(IAsyncResult iAsyncResult) 
     { 
      return; 
     } 
    } 
} 
+0

이 시도하거나 문제가 발생했습니다 알고 있었다, 그러나 나는이에서 오는 문제를 많이 볼 수 없다. 아마도 누군가가 설명 할 수 있습니다. – leppie

답변

5

난 아직 대답이 없어,하지만 난 내가 이상한 입증하는 약간 명확 프로그램을 생각하는 무슨이 :이 어떤 재귀 호출을 포함하지 않는

using System; 

delegate void MyDelegate(); 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     var c = new MyChild(); 
     c.DisplayOddity(); 
     Console.ReadLine(); 
    } 
} 

public class MyParent 
{ 
    public virtual void X() 
    { 
     Console.WriteLine("Executing MyParent.X"); 
    } 
} 

public class MyChild : MyParent 
{ 
    public void DisplayOddity() 
    { 
     MyDelegate md = base.X; 

     Console.WriteLine("Calling Invoke()"); 
     md.Invoke();    // Executes base method... fair enough 

     Console.WriteLine("Calling BeginInvoke()"); 
     md.BeginInvoke(null, null); // Executes overridden method! 
    } 

    public override void X() 
    { 
     Console.WriteLine("Executing MyChild.X"); 
    } 
} 

합니다.

Calling Invoke() 
Executing MyParent.X 
Calling BeginInvoke() 
Executing MyChild.X 

(당신이이 간단한 생식 것을 동의하는 경우, 원래의 질문에 코드를 대체 주시기 내가 내 대답 :

에서 제거 할 수 있습니다 : 결과는 비록 같은 기이 여전히

솔직히 말해서, 이것은 나에게 버그처럼 보입니다. 나는 조금 더 주변을 파헤쳐 보겠다.

+0

BeginInvoke에 대해 생성 된 내부 코드가있는 버그처럼 보입니다. 두 번째 호출의 스택 추적을 살펴보면 위임자 (여전히 MyParent.X)의 메서드 정보의 '정확성'을 확인합니다. – leppie

+0

또 다른 이상한 점은 비동기 호출에 Remoting이 사용되는 이유는 무엇입니까? 정말 간단한 스레드 또는 스레드 풀을 사용할 것이라고 생각했습니다. – leppie

+0

Remoting이 어디에서 수신되는 걸까요? –

0

어쩌면 당신이 찾고있는 대답,하지만이 작동하는 것 같다 :

ThreadPool.QueueUserWorkItem(x => md()); 

또는

new Thread(() => md()).Start(); 

그러나 당신은 당신의 자신의 회계 :(

1

동안을 수행해야합니다 Delegate.Invoke는 델리게이트 메소드를 직접 호출합니다. Delegate.BeginInvoke는 내부적으로 ThreadPool.QueueUserWorkItem()을 사용합니다. md.Invoke()는 기본 클래스의 메소드에 액세스 할 수 있기 때문에 base.X를 호출 할 수있었습니다. base 키워드를 통해 파생 클래스를 얇게 만듭니다. 스레드 풀에 의해 시작된 대리자가 클래스 외부에 있으므로, 아래 코드와 마찬가지로 X 메서드에 대한 참조가 오버로드됩니다. .NET 프레임 워크 코드로



    public class Program 
    { 
     static void Main(string[] args) 
     { 
      MyChild a = new MyChild(); 
      MyDelegate ma = new MyDelegate(a.X); 

      MyParent b = new MyChild(); 
      MyDelegate mb = new MyDelegate(b.X); 

      ma.Invoke(); 
      mb.Invoke(); 
      ma.BeginInvoke(CallBack, null); 
      mb.BeginInvoke(CallBack, null); //all four calls call derived MyChild.X 

      Console.ReadLine(); 
     } 

     public static void CallBack(IAsyncResult iAsyncResult) 
     { 
      return; 
     } 
    } 

디버그 : http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx