почему мы предпочитаем? к ?? оператор в c #?

Недавно я обнаружил, что мы можем использовать? оператора для проверки нhive. Пожалуйста, проверьте приведенные ниже примеры кода:

var res = data ?? new data(); 

Это точно похоже на

  var res = (data==null) ? new data() : data ; 

Я проверил весь исходный repository проекта и некоторые другие проекты с открытым исходным кодом. И это ?? оператор никогда не использовался.

Мне просто интересно, есть ли какие-то причины, такие как проблемы с производительностью или что-то еще?

РЕДАКТИРОВАТЬ:

Я только что обновил свой пример кода на основе комментариев от рекурсивного & Anton. Его ошибка в неосторожности. 🙁

Оператор null coalesce намного яснее при проверке нулевого значения, то есть его основной цели. Он также может быть прикован.

 object a = null; object b = null; object c = new object(); object d = a ?? b ?? c; //d == c. 

Хотя этот оператор ограничен нулевой проверкой, тернарный оператор не является. Например

 bool isQuestion = true; string question = isQuestion ? "Yes" : "No"; 

Я думаю, что люди просто не знают оператора нулевого коалесцента, поэтому вместо этого используют тернарный оператор. Тернар существовал до C # в большинстве языков стиля C, поэтому, если вы не знаете C # внутри и снаружи и / или запрограммированы на другом языке, тройной является естественным выбором. Если вы проверяете значение null, используйте оператор null coalesce, он предназначен для этого, и IL немного оптимизирован (сравните с if if else).

Ниже приведен пример сравнения использования каждого

 object a = null; object b = null; object c = null; object nullCoalesce = a ?? b ?? c; object ternary = a != null ? a : b != null ? b : c; object ifThenElse; if (a != null) ifThenElse = a; else if (b != null) ifThenElse = b; else if (c != null) ifThenElse = c; 

Во-первых, просто посмотрите на синтаксис null coalesce, это путь более ясный. Тернар действительно запутан. Теперь посмотрим на IL

Только Null Coalesce

 .entrypoint .maxstack 2 .locals init ( [0] object a, [1] object b, [2] object c, [3] object nullCoalesce) L_0000: ldnull L_0001: stloc.0 L_0002: ldnull L_0003: stloc.1 L_0004: newobj instance void [mscorlib]System.Object::.ctor() L_0009: stloc.2 L_000a: ldloc.0 L_000b: dup L_000c: brtrue.s L_0015 L_000e: pop L_000f: ldloc.1 L_0010: dup L_0011: brtrue.s L_0015 L_0013: pop L_0014: ldloc.2 L_0015: stloc.3 L_0016: ldloc.3 L_0017: call void [mscorlib]System.Console::WriteLine(object) L_001c: ret 

Только троянец

 .entrypoint .maxstack 2 .locals init ( [0] object a, [1] object b, [2] object c, [3] object ternary) L_0000: ldnull L_0001: stloc.0 L_0002: ldnull L_0003: stloc.1 L_0004: newobj instance void [mscorlib]System.Object::.ctor() L_0009: stloc.2 L_000a: ldloc.0 L_000b: brtrue.s L_0016 L_000d: ldloc.1 L_000e: brtrue.s L_0013 L_0010: ldloc.2 L_0011: br.s L_0017 L_0013: ldloc.1 L_0014: br.s L_0017 L_0016: ldloc.0 L_0017: stloc.3 L_0018: ldloc.3 L_0019: call void [mscorlib]System.Console::WriteLine(object) L_001e: ret 

Если тогда только Else Only

 .entrypoint .maxstack 1 .locals init ( [0] object a, [1] object b, [2] object c, [3] object ifThenElse) L_0000: ldnull L_0001: stloc.0 L_0002: ldnull L_0003: stloc.1 L_0004: newobj instance void [mscorlib]System.Object::.ctor() L_0009: stloc.2 L_000a: ldloc.0 L_000b: brfalse.s L_0011 L_000d: ldloc.0 L_000e: stloc.3 L_000f: br.s L_001a L_0011: ldloc.1 L_0012: brfalse.s L_0018 L_0014: ldloc.1 L_0015: stloc.3 L_0016: br.s L_001a L_0018: ldloc.2 L_0019: stloc.3 L_001a: ldloc.3 L_001b: call void [mscorlib]System.Console::WriteLine(object) L_0020: ret 

IL не является одним из моих сильных сторон, поэтому, возможно, кто-то может отредактировать мой ответ и расширить его. Я собирался объяснить свою теорию, но я бы не стал путать себя и других. Количество LOC одинаково для всех трех, но не все IL-операторы выполняют одинаковый период времени для выполнения.

The ?? оператор (также известный как оператор с нулевой связностью ) менее известен, чем тернарный оператор, поскольку он дебютировал с .NET 2.0 и Nullable Types. Причины не использовать его, вероятно, include в себя не осознание того, что он существует, или более знакомый с тернарным оператором.

Тем не менее, проверка на нуль – это не единственное, для чего подходит тройной оператор, поэтому он не заменяет его как таковой, скорее как лучшую альтернативу для очень конкретной потребности. 🙂

Одна из причин, я могу думать, что этот оператор был представлен в .NET 2.0, поэтому код для .NET 1.1 не может иметь его.

Я согласен с вами, мы должны использовать это чаще.

Ссылка

Основываясь на ответе Боба

 public object nullCoalesce(object a, object b, object c) { return a ?? b ?? c; } public object ternary(object a, object b, object c) { return a != null ? a : b != null ? b : c; } public object ifThenElse(object a, object b, object c) { if (a != null) return a; else if (b != null) return b; else return c; } 

… это IL от релизов …

 .method public hidebysig instance object nullCoalesce( object a, object b, object c) cil managed { .maxstack 8 L_0000: ldarg.1 L_0001: dup L_0002: brtrue.s L_000b L_0004: pop L_0005: ldarg.2 L_0006: dup L_0007: brtrue.s L_000b L_0009: pop L_000a: ldarg.3 L_000b: ret } .method public hidebysig instance object ternary( object a, object b, object c) cil managed { .maxstack 8 L_0000: ldarg.1 L_0001: brtrue.s L_000a L_0003: ldarg.2 L_0004: brtrue.s L_0008 L_0006: ldarg.3 L_0007: ret L_0008: ldarg.2 L_0009: ret L_000a: ldarg.1 L_000b: ret } .method public hidebysig instance object ifThenElse( object a, object b, object c) cil managed { .maxstack 8 L_0000: ldarg.1 L_0001: brfalse.s L_0005 L_0003: ldarg.1 L_0004: ret L_0005: ldarg.2 L_0006: brfalse.s L_000a L_0008: ldarg.2 L_0009: ret L_000a: ldarg.3 L_000b: ret } 

Одна из причин (как другие уже коснулись), вероятно, будет недостаточной осведомленностью. Это также может быть (как и в моем собственном случае), желание сохранить количество подходов, чтобы как можно больше сделать подобные вещи в кодовой базе. Поэтому я стараюсь использовать тернарный оператор для всех компактных ситуаций if-a-condition-is-met-do-this-else-do-this.

Например, я нахожу следующие два утверждения довольно похожими на концептуальном уровне:

 return a == null ? string.Empty : a; return a > 0 ? a : 0; 

Я думаю, что это просто привычка с других языков. НАСКОЛЬКО МНЕ ИЗВЕСТНО, ?? оператор не используется ни на каком другом языке.

Я бы подумал, что эквивалент

 var res = data ?? data.toString(); 

было бы

 var res = (data!=null) ? data : data.toString();