Использует ли Action.Invoke наилучшую практику?
Если у меня есть код ниже, нужно ли просто вызвать действие или вызвать его действие .Invoke?
public class ClassA
{
public event Action<string> OnAdd;
private void SomethingHappened()
{
if (OnAdd != null)
OnAdd("It Happened"); //Should it be OnAdd.Invoke("It Happened") ???????
}
}
public class ClassB
{
public ClassB()
{
var myClass = new ClassA();
myClass.OnAdd += Add;
}
private void Add(string Input)
{
//do something
}
}
Ответы
Ответ 1
Оба эквивалентны, компилятор преобразует OnAdd("It Happened");
в OnAdd.Invoke("It Happened");
для вас.
Я предполагаю, что это вопрос предпочтения, однако я лично предпочитаю форму терьера.
В стороне, как правило, предпочтительнее взять локальную копию делегата уровня класса, прежде чем вызывать его, чтобы избежать условия гонки, при которой OnAdd
не является нулевым в момент проверки, но в то время он вызывается:
private void SomethingHappened()
{
Action<string> local = OnAdd;
if (local != null)
{
local("It Happened");
}
}
Ответ 2
Две конструкции отлично эквивалентны.
OnAdd("It Happened");
- это просто синтаксический сахар. За кулисами компилятор выдает вызов Action<T>.Invoke
в полученной MSIL. Поэтому используйте тот, который вам больше читается (для меня OnAdd("It Happened");
достаточно читабельно).
Ответ 3
Они точно эквивалентны, если вы не столкнетесь с очень странной ошибкой анонимных функций.
Лично я обычно использую форму ярлыка, но иногда из-за этого становится более читаемым, чтобы явно вызвать Invoke
. Например, у вас может быть:
if (callAsync)
{
var result = foo.BeginInvoke(...);
// ...
}
else
{
foo.Invoke(...);
// ...
}
Здесь явное использование Invoke
полезно для симметрии.
См. раздел 15.4 спецификации С# 4 для получения дополнительной информации о вызове делегата, хотя он явно не указывает его в терминах вызова метода Invoke
.
Ответ 4
Что-то я заметил на этом с последним выпуском С# 6, поскольку он может поощрять Invoke
использовать больше и думал, что добавлю его к этому старому вопросу, если он кому-то поможет:
"Старый" способ:
Action<string> doSomething = null; // or not null
if (doSomething != null)
doSomething("test");
Возможный прагматический способ (аналогично шаблону делегата пустого события):
Action<string> doSomethingPragmatic = s => { }; // empty - might be overwritten later
doSomethingPragmatic("test");
С# 6:
Action<string> doSomethingCs6 = null; // or not null
doSomethingCs6?.Invoke("test");
// Not valid C#:
// doSomethingCs6?("test")
// doSomethingCs6?.("test")