2008-10-23 1 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 

(Если вы согласны, что это проще, репродукция, не стесняйтесь, чтобы заменить код в исходный вопрос, и я удалить его из моего ответа :)

Если честно, это выглядит как ошибка для меня. Я буду копать немного больше.

+0

Похоже на ошибку с внутренним кодом, созданным для BeginInvoke. Посмотрев на стеке второго вызова, подтвердите «правильность» информации о методе в делетете (еще MyParent.X). – leppie 2008-10-23 13:03:35

0

Может быть, не ответ, который вы ищете, но это похоже на работу:

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

или

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

Но вам нужно будет сделать свой собственный учет :(

1

While 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

Смежные вопросы