2008-10-23 54 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 2008-10-23 12:22:39

回答

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 

(如果你認爲這是一個簡單的攝製,隨意替換原來的問題的代碼,我會從我的答案:)

刪除

說實話,這看起來像是一個bug。我會多挖一點。

+0

它看起來像一個爲BeginInvoke生成的內部代碼的錯誤。查看第二次調用的堆棧跟蹤,確認委託中方法信息的「正確性」(仍爲MyParent.X)。 – leppie 2008-10-23 13:03:35

0

也許不是你正在尋找的答案,但是這似乎工作:

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

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

但你需要做你自己的會計:(

1

雖然Delegate.Invoke直接調用委託方法,Delegate.BeginInvoke內部使用ThreadPool.QueueUserWorkItem()。md.Invoke()只能調用base.X,因爲可以訪問基類的方法wi通過base關鍵字細化派生類。由於由線程池啓動的委託對於類是外部的,因此對其X方法的引用將受到重載,就像下面的代碼一樣。



    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; 
     } 
    } 

調試到.NET Framework代碼:http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

相關問題