Плохое использование нулевого оператора объединения?

myFoo = myFoo ?? new Foo();

вместо

if (myFoo == null) myFoo = new Foo();

Правильно ли я думаю, что первая строка кода всегда будет выполнять присваивание? Кроме того, это плохое использование оператора объединения с нулевым значением?


person Chris    schedule 24.11.2009    source источник
comment
Вы приводите убедительный аргумент в пользу оператора ??= :)   -  person Pavel Minaev    schedule 27.11.2009
comment
@PavelMinaev в данном случае, разве это не идентично оператору ||=? Ему пришлось бы заменить вызов if (!isset(myFoo)) myFoo = new Foo();, чтобы гарантировать собственный оператор.   -  person Charlie Harding    schedule 23.12.2015
comment
Это не идентично, так как || требует логического значения.   -  person Pavel Minaev    schedule 23.12.2015
comment
(Вы случайно не путаете это с PHP? Обратите внимание, что вопрос помечен как C#.)   -  person Pavel Minaev    schedule 23.12.2015


Ответы (3)


Я сравнил CIL сгенерированного кода (обязательно выполнив сборку Release — с установленным флажком «Оптимизировать код» в свойствах проекта, что соответствует переключателю /optimize на csc.exe). Вот что я получил (используя VS 2008 - обратите внимание, что Foo.MaybeFoo() - это метод, который иногда возвращает null, иногда Foo)

GetFooWithIf:

  IL_0000:  call       class Application3.Foo Application3.Foo::MaybeFoo()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  brtrue.s   IL_000f
  IL_0009:  newobj     instance void Application3.Foo::.ctor()
  IL_000e:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  ret

GetFooWithCoalescingOperator:

  IL_0000:  call       class Application3.Foo Application3.Foo::MaybeFoo()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  dup
  IL_0008:  brtrue.s   IL_0010
  IL_000a:  pop
  IL_000b:  newobj     instance void Application3.Foo::.ctor()
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  ret

Таким образом, то же самое, за исключением дополнительного дублирования вершины стека и всплывающего окна. Если это может привести к измеримой разнице в производительности, я куплю шляпу специально для того, чтобы ее съесть; поэтому используйте тот, который, по вашему мнению, обеспечивает лучшую читабельность.

(редактировать) о, и JITter может быть достаточно умен, чтобы избавиться даже от этой разницы!

person AakashM    schedule 24.11.2009
comment
Это с csc.exe /optimize+? - person Pavel Minaev; 27.11.2009
comment
Я не знаю, насколько большой Фу на самом деле. Влияет ли его размер на время запуска dup & pop? - person Gary; 13.07.2012
comment
@ Гэри в коде здесь было class, и все ссылки на объекты имеют одинаковый размер. Я уверен, что с struct вы получите другой код. Но нам рекомендуется держать structs максимум в 16 байт, так что не намного хуже. - person AakashM; 13.07.2012

Я не думаю, что это плохое использование оператора объединения с нулевым значением. При чтении кода он максимально краток и лаконичен, а цель кода очевидна.

Это правильно, что с помощью такого оператора объединения с нулевым значением вы всегда будете получать присваивание, но я бы не беспокоился об этом. (И если это действительно окажется проблемой с производительностью, вы уже знаете, как это исправить).

person driis    schedule 24.11.2009

Вы правы в том, что первая строка всегда будет делать присваивание. Я бы не беспокоился об этом, если бы код не выполнялся очень часто.

person Fredrik Mörk    schedule 24.11.2009
comment
Что должно помешать компилятору оптимизировать его? - person Timbo; 24.11.2009
comment
@Timbo: я не слишком хорошо разбираюсь в том, какие оптимизации компилятор может или не может выполнять, но я предполагаю, что myFoo будет использоваться в другом месте кода и что это не позволит компилятору его оптимизировать. Если он не используется в другом месте, это другая история. - person Fredrik Mörk; 24.11.2009