2008-10-23 16 views
7

Bất cứ ai có thể cho tôi biết tại sao mã này hoạt động theo cách đó? Xem các nhận xét được nhúng trong mã ...Gọi() và BeginInvoke() hoạt động khác khi thực hiện một phương thức có thể ghi đè thông qua một đại biểu

Tôi có thiếu thứ gì đó thực sự rõ ràng ở đây không?

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

tôi đã không cố gắng này, hoặc đã biết có một vấn đề, nhưng tôi có thể nhìn thấy rất nhiều vấn đề đến từ này. Có lẽ ai đó có thể giải thích :) – leppie

Trả lời

5

Tôi không có một câu trả lời nào, nhưng tôi có những gì tôi tin là một chương trình một chút rõ ràng để chứng minh kỳ quặc:

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

này không liên quan đến bất kỳ cuộc gọi đệ quy. Kết quả vẫn là như nhau kỳ quặc mặc dù:

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

(Nếu bạn đồng ý rằng đây là một repro đơn giản hơn, cảm thấy tự do để thay thế mã trong câu hỏi ban đầu và tôi sẽ loại bỏ nó từ câu trả lời của tôi :)

Thành thật mà nói, điều này trông giống như một lỗi đối với tôi. Tôi sẽ đào nhiều hơn một chút.

+0

Dường như một lỗi với mã nội bộ được tạo cho BeginInvoke. Nhìn vào stacktrace của cuộc gọi thứ 2, xác nhận 'đúng đắn' của thông tin phương pháp trong đại biểu (vẫn là MyParent.X). – leppie

+0

Một điều kỳ quặc khác là, tại sao Remoting được sử dụng cho cuộc gọi không đồng bộ? Tôi thực sự nghĩ rằng nó sẽ chỉ sử dụng một thread đơn giản hoặc threadpool. – leppie

+0

Bạn thấy Từ xa đến từ đâu? –

0

Có lẽ không phải là câu trả lời bạn đang tìm kiếm, nhưng điều này dường như làm việc:

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

hoặc

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

Nhưng bạn sẽ cần phải làm kế toán của riêng bạn :(

1

Trong khi Delegate.Invoke gọi phương thức ủy nhiệm trực tiếp, Delegate.BeginInvoke sử dụng nội bộ ThreadPool.QueueUserWorkItem() .md.Invoke() chỉ có thể gọi base.X vì các phương thức của lớp cơ sở có thể truy cập được mỏng lớp dẫn xuất thông qua từ khóa cơ sở. Vì đại biểu bắt đầu bởi nhóm luồng nằm ngoài lớp của bạn, tham chiếu đến phương thức X của nó bị quá tải, giống như mã bên dưới.



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

gỡ lỗi vào mã .NET Framework: http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

Các vấn đề liên quan