MethodInvoker против действия для Control.BeginInvoke

Что более правильно и почему?

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

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

или

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

Мне кажется, что я делаю то же самое, поэтому, когда самое подходящее время для использования MethodInvoker vs Action или даже для написания лямбда-выражения?

EDIT: Я знаю, что на самом деле нет большой разницы между написанием лямбды vs Action, но MethodInvoker, похоже, сделано для определенной цели. Это что-то другое?

Ответ 1

Оба одинаково правильны, но в документации для Control.Invoke указано, что:

Делегат может быть примером EventHandler, и в этом случае отправитель параметр будет содержать этот элемент управления, и параметр события будет содержать EventArgs.Empty. Делегат также может быть примером MethodInvoker, или любой другой делегат, который принимает пустоту список параметров. Призыв к Участник EventHandler или MethodInvoker будет быстрее, чем вызов другому тип делегата.

Итак, MethodInvoker будет более эффективным выбором.

Ответ 2

Для каждого решения ниже я запускаю итерации 131072 (128 * 1024) (в одном отдельном потоке). Помощник по производительности VS2010 дает следующие результаты:

  • Только для чтения MethodInvoker: 5664.53 (+0%)
  • Новый методInvoker: 5828.31 (+2.89%)
  • функция cast in MethodInvoker: 5857.07 (+3.40%)
  • только для чтения Действие: 6467.33 (+14.17%)
  • Новое действие: 6829.07 (+20.56%)

Вызов нового Action на каждой итерации

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

Вызов в конструктор конструктора, доступный только для чтения, Действие на каждой итерации

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

Вызовите новый MethodInvoker на каждой итерации.

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

Вызов в конструктор конструктора, доступный только для чтения, MethodInvoker на каждой итерации

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

Вызов функции, отличной в MethodInvoker на каждой итерации

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

Пример вызова для решения "Новое действие":

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

Ответ 3

Я предпочитаю использовать lambdas и Actions/Funcs:

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));

Ответ 4

Действие определено в System, а MethodInvoker определено в System.Windows.Forms - вам может быть лучше использовать Action, поскольку он переносится в другие места. Вы также найдете больше мест, принимающих действие в качестве параметра, чем MethodInvoker.

Однако документация показывает, что вызовы делегатов типа EventHandler или MethodInvoker в Control.Invoke() будут быстрее, чем любой другой тип.

Помимо имени имени, в котором они находятся, я не верю, что существует значимое функциональное различие между Action и MethodInvoker - они по существу определяются как:

public delegate void NoParamMethod();

Как и в стороне, Action имеет несколько перегрузок, которые позволяют передавать параметры, - и он является общим, так что они могут быть типичными.

Ответ 5

Также в MSDN:

MethodInvoker предоставляет простой делегат, который используется для вызова метода с помощью списка параметров void. Этот делегат может использоваться при вызове метода Invoke для управления или когда вам нужен простой делегат, но вы не хотите его определять самостоятельно.

a Действие, с другой стороны, может принимать до 4 параметров.

Но я не думаю, что существует разница между MethodInvoker и Action, поскольку они оба просто инкапсулируют делегат, который не принимает paremter, и возвращает недействительным

Если вы посмотрите на их определения, вы просто увидите это.

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

Кстати, вы также можете написать вторую строку как.

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

Ответ 6

В большинстве случаев это зависит от предпочтений, если вы не собираетесь повторно использовать метод DoSomething(). Также анонимные функции помещают ваши скопированные переменные в кучу, могут сделать ее более дорогой функцией.

Ответ 7

Не забудьте как-то проверить, доступно ли управление на данный момент, чтобы избежать ошибок при закрытии формы.

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));