MethodInvoker vs Action for Control.BeginInvoke
Asked Answered
D

7

67

Which is more correct and why?

Control.BeginInvoke(new Action(DoSomething), null);

private void DoSomething()
{
    MessageBox.Show("What a great post");
}

or

Control.BeginInvoke((MethodInvoker) delegate { 
    MessageBox.Show("What a great post");
}); 

I kinda feel like I am doing the same thing, so when is the right time to use MethodInvoker vs Action, or even writing a lambda expression?

EDIT: I know that there isn't really much of a difference between writing a lambda vs Action, but MethodInvoker seems to be made for a specific purpose. Is it doing anything different?

Druci answered 22/7, 2009 at 19:47 Comment(1)
Look at this as well mark-dot-net.blogspot.com.uy/2014/07/…Quieten
C
87

Both are equally correct, but the documentation for Control.Invoke states that:

The delegate can be an instance of EventHandler, in which case the sender parameter will contain this control, and the event parameter will contain EventArgs.Empty. The delegate can also be an instance of MethodInvoker, or any other delegate that takes a void parameter list. A call to an EventHandler or MethodInvoker delegate will be faster than a call to another type of delegate.

So MethodInvoker would be a more efficient choice.

Clearance answered 22/7, 2009 at 19:55 Comment(2)
Thanks Jon, but what makes MethodInvoker more efficient than a call to Action with no arguments?Druci
Simply: it sounds like it checks (as special cases) for these two with an is/as check, and uses Invoke, rather than DynamicInvoke - which is significantly fasterRealgar
T
31

For each solution bellow I run a 131072 (128*1024) iterations (in one separated thread). The VS2010 performance assistant give this results:

  • read-only MethodInvoker: 5664.53 (+0%)
  • New MethodInvoker: 5828.31 (+2.89%)
  • function cast in MethodInvoker: 5857.07 (+3.40%)
  • read-only Action: 6467.33 (+14.17%)
  • New Action: 6829.07 (+20.56%)

Call to a new Action at each iteration

    private void SetVisibleByNewAction()
    {
        if (InvokeRequired)
        {
            Invoke(new Action(SetVisibleByNewAction));
        }
        else
        {
            Visible = true;
        }
    }

Call to a read-only, build in constructor, Action at each iteration

    // private readonly Action _actionSetVisibleByAction
    // _actionSetVisibleByAction= SetVisibleByAction;
    private void SetVisibleByAction()
    {
        if (InvokeRequired)
        {
            Invoke(_actionSetVisibleByAction);
        }
        else
        {
            Visible = true;
        }
    }

Call to a new MethodInvoker at each iteration.

    private void SetVisibleByNewMethodInvoker()
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(SetVisibleByNewMethodInvoker));
        }
        else
        {
            Visible = true;
        }
    }

Call to a read-only, build in constructor, MethodInvoker at each iteration

    // private readonly MethodInvoker _methodInvokerSetVisibleByMethodInvoker 
    // _methodInvokerSetVisibleByMethodInvoker = SetVisibleByMethodInvoker;
    private void SetVisibleByMethodInvoker()
    {
        if (InvokeRequired)
        {
            Invoke(_methodInvokerSetVisibleByMethodInvoker);
        }
        else
        {
            Visible = true;
        }
    }

Call to the function cast in MethodInvoker at each iteration

    private void SetVisibleByDelegate()
    {
        if (InvokeRequired)
        {
            Invoke((MethodInvoker) SetVisibleByDelegate);
        }
        else
        {
            Visible = true;
        }
    }

Example of call for the "New Action" solution :

    private void ButtonNewActionOnClick(object sender, EventArgs e)
    {
        new Thread(TestNewAction).Start();
    }

    private void TestNewAction()
    {
        var watch = Stopwatch.StartNew();
        for (var i = 0; i < COUNT; i++)
        {
            SetVisibleByNewAction();
        }
        watch.Stop();
        Append("New Action: " + watch.ElapsedMilliseconds + "ms");
    }
Trixie answered 17/9, 2014 at 9:16 Comment(1)
How do you read this result? I'm new to profiling. A link will be helpful.Jun
W
13

I prefer using lambdas and Actions/Funcs:

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));
Whereunto answered 22/7, 2009 at 19:56 Comment(0)
N
9

Action is defined in System, while MethodInvoker is defined in System.Windows.Forms - you may be better off using Action, since it is portable to other places. You will also find more places that accept Action as a parameter than MethodInvoker.

However, the documentation does indicate that calls to delegates of type EventHandler or MethodInvoker in Control.Invoke() will be faster than any other type.

Aside from which namepsace they are in, I don't believe there is a meaningful functional difference between Action and MethodInvoker - they are essentially both defined as:

public delegate void NoParamMethod();

As an aside, Action has several overloads which allow parameters to be passed in - and it is generic so that they can be typesafe.

Nakesha answered 22/7, 2009 at 19:54 Comment(0)
F
3

Also per MSDN:

MethodInvoker provides a simple delegate that is used to invoke a method with a void parameter list. This delegate can be used when making calls to a control's Invoke method, or when you need a simple delegate but do not want to define one yourself.

an Action on the other hand can take up to 4 parameters.

But I don't think there is any difference between MethodInvoker and Action as they both simply encapsulate a delegate that doesn't take a paremter and returns void

If you look at their definitions you'll simply see this.

public delegate void MethodInvoker();
public delegate void Action();

btw you could also write your second line as.

Control.BeginInvoke(new MethodInvoker(DoSomething), null);
Feck answered 22/7, 2009 at 19:54 Comment(2)
you can even rewrite it as: Control.BeginInvoke(new MethodInvoker(DoSomething)); or Control.BeginInvoke(new MethodInvoker(() => { DoSomething(); }));Nickienicklaus
According to the documentation, Action can take up to 16 parameters. learn.microsoft.com/en-us/dotnet/api/…Darlleen
A
2

It is a matter of preference in most cases, unless you intend to reuse the DoSomething() method. Also the anonymous functions will place your scoped variables on the heap, might make it a more expensive function.

Argueta answered 22/7, 2009 at 19:51 Comment(0)
C
1

Don't forget to somehow check if control is available at the moment, to avoid errors at closing form.

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));
Callao answered 20/12, 2017 at 11:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.