Есть ли в следующем коде состояние гонки, которое может привести к NullReferenceException
?
-- or --
Возможно ли, чтобы для переменной Callback
было установлено значение null после того, как оператор объединения с нулевым значением проверит нулевое значение, но до вызова функции?
class MyClass {
public Action Callback { get; set; }
public void DoCallback() {
(Callback ?? new Action(() => { }))();
}
}
ИЗМЕНИТЬ
Это вопрос, который возник из любопытства. Обычно я так не пишу.
Меня не беспокоит, что переменная Callback
устареет. Меня беспокоит, что Exception
вылетит из DoCallback
.
ИЗМЕНИТЬ №2
Вот мой класс:
class MyClass {
Action Callback { get; set; }
public void DoCallbackCoalesce() {
(Callback ?? new Action(() => { }))();
}
public void DoCallbackIfElse() {
if (null != Callback) Callback();
else new Action(() => { })();
}
}
Метод DoCallbackIfElse
имеет состояние гонки, которое может вызвать NullReferenceException
. У метода DoCallbackCoalesce
такое же состояние?
А вот вывод IL:
MyClass.DoCallbackCoalesce:
IL_0000: ldarg.0
IL_0001: call UserQuery+MyClass.get_Callback
IL_0006: dup
IL_0007: brtrue.s IL_0027
IL_0009: pop
IL_000A: ldsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate1
IL_000F: brtrue.s IL_0022
IL_0011: ldnull
IL_0012: ldftn UserQuery+MyClass.<DoCallbackCoalesce>b__0
IL_0018: newobj System.Action..ctor
IL_001D: stsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate1
IL_0022: ldsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate1
IL_0027: callvirt System.Action.Invoke
IL_002C: ret
MyClass.DoCallbackIfElse:
IL_0000: ldarg.0
IL_0001: call UserQuery+MyClass.get_Callback
IL_0006: brfalse.s IL_0014
IL_0008: ldarg.0
IL_0009: call UserQuery+MyClass.get_Callback
IL_000E: callvirt System.Action.Invoke
IL_0013: ret
IL_0014: ldsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate3
IL_0019: brtrue.s IL_002C
IL_001B: ldnull
IL_001C: ldftn UserQuery+MyClass.<DoCallbackIfElse>b__2
IL_0022: newobj System.Action..ctor
IL_0027: stsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate3
IL_002C: ldsfld UserQuery+MyClass.CS$<>9__CachedAnonymousMethodDelegate3
IL_0031: callvirt System.Action.Invoke
IL_0036: ret
Мне кажется, что call UserQuery+MyClass.get_Callback
вызывается только один раз при использовании оператора ??
и дважды при использовании if...else
. Я делаю что-то неправильно?
??
не является тернарным или тернарным оператором. Это оператор объединения с нулем, который является бинарным оператором (т.е. принимает 2 операнда, а не 3). Тернарный условный оператор?:
. - person BoltClock   schedule 12.05.2012