Нулевой оператор объединения кэширует результат в С#

Я знаю, что выполнение (myValue ?? new SomeClass()) похоже на (myValue == null ? new SomeClass() : myValue)

Но из любопытства, есть ли какое-либо преимущество в производительности, когда я вызываю функцию, скажем (getResult() ?? new SomeClass()). Будет ли getResult() выполняться дважды? Это кажется неинтуитивным, поскольку я указал вызов метода только один раз.

Ответ 1

Ну, если "кэшированием" вы хотите сохранить его во временной переменной, тогда да.

Эта конструкция:

var result = (getResult() ?? new SomeClass());

можно считать эквивалентным этому:

var <temp> = getResult();
if (<temp> == null)
    <temp> = new SomeClass();
result = <temp>;

Это также говорит о том, что вторая часть, операнд после ?? вообще не выполняется, если первый операнд не является null.

Итак, чтобы ответить на ваши конкретные вопросы:

  • Каждый операнд оценивается не более одного раза
  • Второй операнд оценивается только в том случае, если первый оценивает значение null

Заметьте также, что вы можете связать их:

var result = first() ?? second() ?? third() ?? fourth();

Результат:

  • Вычисляет first()
  • Если first() оценивается как null, оценивается second()
  • Если second() оценивается как null, то оценивает third()
  • Если все вышеперечисленное оценивается как null, в итоге оценивается fourth

В результате получается первое (не предназначенное для каламбур) ненулевое значение.


Этот тип кода скоро станет еще лучше в новом С# с новым оператором ?.:

var result = first?.second?.third;

Это базовая обработка ., т.е. он будет читать член second first, а затем член third любого second, но он остановится при первом null, а также обязательно будет оценивать каждый шаг только один раз:

(obj as IDisposable)?.Dispose();

obj as IDisposable будет оцениваться только один раз.

TryGetObjectToSave()?.Save();

Вызов только TryGetObjectToSave() один раз, и если он что-то вернет, метод Save() для этого будет вызван.