Есть ли разница между этими двумя строками?
MyName = (s.MyName == null) ? string.Empty : s.MyName
или
MyName = s.MyName ?? string.Empty
Есть ли разница между этими двумя строками?
MyName = (s.MyName == null) ? string.Empty : s.MyName
или
MyName = s.MyName ?? string.Empty
UPDATE: я написал сообщение в блоге, которое более подробно обсуждает эту тему. http://www.codeducky.org/properties-fields-and-methods-oh-my/
Как правило, они возвращают тот же результат. Тем не менее, есть несколько случаев, когда вы ощутите заметные различия, когда MyName
является свойством, поскольку геттер MyName
будет выполняться дважды в первом примере и только один раз во втором примере.
Например, вы можете столкнуться с различиями в производительности от выполнения MyName
дважды:
string MyName
{
get
{
Thread.Sleep(10000);
return "HELLO";
}
}
Или вы можете получить разные результаты при выполнении MyName
дважды, если MyName
имеет статус:
private bool _MyNameHasBeenRead = false;
string MyName
{
get
{
if(_MyNameHasBeenRead)
throw new Exception("Can't read MyName twice");
_MyNameHasBeenRead = true;
Thread.Sleep(10000);
return "HELLO";
}
}
Или вы можете получить разные результаты от выполнения MyName
дважды, если MyName
можно изменить в другом потоке:
void ChangeMyNameAsync()
{
//MyName set to null in another thread which makes it
//possible for the first example to return null
Task.Run(() => this.MyName = null);
}
string MyName { get; set; }
Здесь как скомпилирован фактический код. Сначала кусок с тройным выражением:
IL_0007: ldloc.0 // s
IL_0008: callvirt s.get_MyName <-- first call
IL_000D: brfalse.s IL_0017
IL_000F: ldloc.0 // s
IL_0010: callvirt s.get_MyName <-- second call
IL_0015: br.s IL_001C
IL_0017: ldsfld System.String.Empty
IL_001C: call set_MyName
и вот кусок с нулевым коалесцирующим оператором:
IL_0007: ldloc.0 // s
IL_0008: callvirt s.get_MyName <-- only call
IL_000D: dup
IL_000E: brtrue.s IL_0016
IL_0010: pop
IL_0011: ldsfld System.String.Empty
IL_0016: call s.set_MyName
Как вы можете видеть, скомпилированный код для тернарного оператора сделает два вызова, чтобы получить значение свойства, тогда как оператор с нулевым коалесцированием будет делать только 1.
Если свойство больше, чем простой getter, вы можете выполнить функцию дважды в случае, отличном от нуля, для первого.
Если свойство находится в объекте с сохранением состояния, то второй вызов свойства может возвращать другой результат:
class MyClass
{
private IEnumerator<string> _next = Next();
public MyClass()
{
this._next.MoveNext();
}
public string MyName
{
get
{
var n = this._next.Current;
this._next.MoveNext();
return n;
}
}
public static IEnumerator<string> Next()
{
yield return "foo";
yield return "bar";
}
}
Кроме того, в случае, отличном от строки, класс может перегрузить ==, чтобы сделать что-то другое, чем троичный оператор. Я не считаю, что тернарный оператор может быть перегружен.
Единственное различие заключается в том, вы оцениваете s.MyName
дважды или один раз. Первый будет делать это дважды в случае, если s.MyName
не является нулевым, второй будет оценивать его только один раз.
В большинстве случаев это различие не имеет значения, и я бы пошел со вторым, потому что он более понятен и краток.
Да, оба они одинаковы, и это оператор с нулевой связностью.
Он возвращает левый операнд, если операнд не равен нулю; в противном случае он возвращает правый операнд.
Если говорить об эффективности, то
string MyName = (s.MyName == null) ? string.Empty : s.MyName;
string MyName2 = s.MyName ?? string.Empty;
Если я использую дизассемблер, тогда я вижу, что для первого оператора требуется 19 операторов, которые должны быть выполнены компилятором, тогда как второй оператор требовал выполнения только 12 операторов.
Да, они делают то же самое. ??
является сокращением для проверки нулевого значения.
Они выполняют ту же задачу.
Единственное отличие было бы читабельностью относительно того, понимают ли ваши коллеги или кто читает код, синтаксис.
EDIT: Кроме того, первый вариант может дважды оценить свойство MyName
.
Нет. Оба делают то же самое. Второй - эффективный. Возвращает фактическое значение, если оно не равно нулю. Иначе будет возвращено значение правой стороны.
Обратитесь к http://msdn.microsoft.com/en-us/library/ms173224.aspx
Надеюсь, что это поможет.