Вызов метода, если не пустой в C#

При обновлении SonarQube вы должны подготовиться к некоторым (большим) изменениям. Между 4.5.4 и 6.7.5 существует большой разрыв, поэтому не удивляйтесь, что шашки были улучшены и серьезность пересмотрена.

Это нормально, и вам следует проанализировать изменения перед выполнением любого обновления приложения.

82
задан shA.t 15 February 2016 в 07:31
поделиться

6 ответов

From C# 6 onwards, you can just use:

MyEvent?.Invoke();

or:

obj?.SomeMethod();

The ?. is the null-propagating operator, and will cause the .Invoke() to be short-circuited when the operand is null. The operand is only accessed once, so there is no risk of the "value changes between check and invoke" problem.

===

Prior to C# 6, no: there is no null-safe magic, with one exception; extension methods - for example:

public static void SafeInvoke(this Action action) {
    if(action != null) action();
}

now this is valid:

Action act = null;
act.SafeInvoke(); // does nothing
act = delegate {Console.WriteLine("hi");}
act.SafeInvoke(); // writes "hi"

In the case of events, this has the advantage of also removing the race-condition, i.e. you don't need a temporary variable. So normally you'd need:

var handler = SomeEvent;
if(handler != null) handler(this, EventArgs.Empty);

but with:

public static void SafeInvoke(this EventHandler handler, object sender) {
    if(handler != null) handler(sender, EventArgs.Empty);
}

we can use simply:

SomeEvent.SafeInvoke(this); // no race condition, no null risk
138
ответ дан 24 November 2019 в 09:10
поделиться

События могут быть инициализированы с помощью пустого делегата по умолчанию, который никогда не удаляется:

public event EventHandler MyEvent = delegate { };

Нет необходимости в проверке нуля.

[ Обновление , спасибо Бевану за указание на это]

Однако имейте в виду возможное влияние на производительность. Проведенный мною небольшой тест показал, что обработка события без подписчиков происходит в 2-3 раза медленнее при использовании шаблона «делегат по умолчанию». (На моем двухъядерном ноутбуке с тактовой частотой 2,5 ГГц это означает 279 мс: 785 мс для сбора 50 миллионов событий без подписки.) Это может быть проблемой для горячих точек приложений.

4
ответ дан 24 November 2019 в 09:10
поделиться

This article by Ian Griffiths gives two different solutions to the problem that he concludes are neat tricks that you should not use.

2
ответ дан 24 November 2019 в 09:10
поделиться

В C # для этого есть малоизвестный нулевой оператор ??. Может быть полезно:

http://weblogs.asp.net/scottgu/archive/2007/09/20/the-new-c-null-coalescing-operator-and-using-it-with-linq.aspx

-4
ответ дан 24 November 2019 в 09:10
поделиться

Cerating extention method like one suggested does not really solve issues with race conditions, but rather hide them.

public static void SafeInvoke(this EventHandler handler, object sender)
{
    if (handler != null) handler(sender, EventArgs.Empty);
}

As stated this code is the elegant equivalent to solution with temporary variable, but...

The problem with both that it's possible that subsciber of the event could be called AFTER it has unsubscribed from the event. This is possible because unsubscription can happen after delegate instance is copied to the temp variable (or passed as parameter in the method above), but before delegate is invoked.

In general the behaviour of the client code is unpredictable in such case: component state could not allow to handle event notification already. It's possible to write client code in the way to handle it, but it would put unnecesssary responsibility to the client.

The only known way to ensure thread safity is to use lock statement for the sender of the event. This ensures that all subscriptions\unsubscriptions\invocation are serialized.

To be more accurate lock should be applied to the same sync object used in add\remove event accessor methods which is be default 'this'.

2
ответ дан 24 November 2019 в 09:10
поделиться

Maybe not better but in my opinion more readable is to create an extension method

public static bool IsNull(this object obj) {
 return obj == null;
}
0
ответ дан 24 November 2019 в 09:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: