Подтвердить что ты не робот

Использует ли 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
  }  
}
4b9b3361

Ответ 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")