Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke() and BeginInvoke() behaving differently when executing an overridable method via a delegate

Can anyone tell me why this code behaves the way it does? See comments embedded in the code...

Am I missing something really obvious here?

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;
        }
    }
}
like image 587
Patrick Simpe-Asante Avatar asked Oct 23 '08 12:10

Patrick Simpe-Asante


People also ask

What is the difference between Invoke and BeginInvoke method in C#?

Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the event queue of the Dispatcher at the specified DispatcherPriority. BeginInvoke is asynchronous; therefore, control returns immediately to the calling object after it is called.

Which delegate class is used to specify a function to be called automatically after the function that is invoked by Delegateobject BeginInvoke?

AsyncCallback delegate object, it's target will automatically be called when the asynchronous call is complete.

What is BeginInvoke?

BeginInvoke(Action) Executes the specified delegate asynchronously on the thread that the control's underlying handle was created on. BeginInvoke(Delegate) Executes the specified delegate asynchronously on the thread that the control's underlying handle was created on.


1 Answers

I don't have an answer yet, but I have what I believe to be a slightly clearer program to demonstrate the oddity:

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

This doesn't involve any recursive calls. The result is still the same oddity though:

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

(If you agree that this is a simpler repro, feel free to replace the code in the original question and I'll remove it from my answer :)

To be honest, this looks like a bug to me. I'll dig around a bit more.

like image 187
Jon Skeet Avatar answered Oct 03 '22 12:10

Jon Skeet