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