这两条线之间有区别吗?
MyName = (s.MyName == null) ? string.Empty : s.MyName
Run Code Online (Sandbox Code Playgroud)
要么
MyName = s.MyName ?? string.Empty
Run Code Online (Sandbox Code Playgroud)
Ste*_*ler 166
更新:我写了一篇博文,更深入地讨论了这个主题. http://www.codeducky.org/properties-fields-and-methods-oh-my/
通常他们会返回相同的结果.但是,在某些情况下,当MyName属性属性时,您会遇到明显的差异,因为MyName在第一个示例中,getter将执行两次,而在第二个示例中只执行一次.
例如,您可能会遇到执行MyName两次性能差异:
string MyName
{
get
{
Thread.Sleep(10000);
return "HELLO";
}
}
Run Code Online (Sandbox Code Playgroud)
或者,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";
}
}
Run Code Online (Sandbox Code Playgroud)
或者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; }
Run Code Online (Sandbox Code Playgroud)
这是实际代码的编译方式.首先是三元表达式:
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
Run Code Online (Sandbox Code Playgroud)
这是使用null-coalescing运算符的部分:
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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,三元运算符的编译代码将进行两次调用以获取属性值,而null-coalescing运算符仅执行1.
Dan*_*her 26
如果属性不仅仅是一个简单的getter,那么对于第一个函数,你可能会在非null情况下执行两次函数.
如果属性位于有状态对象中,则对属性的第二次调用可能会返回不同的结果:
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";
}
}
Run Code Online (Sandbox Code Playgroud)
此外,在非字符串的情况下,类可能会重载==以执行与三元运算符不同的操作.我不相信三元运算符可能会过载.
唯一的区别是你评估s.MyName两次还是一次.第一个将在s.MyName非空的情况下执行两次,第二个将只评估一次.
在大多数情况下,这种差异并不重要,我会选择第二种,因为它更清晰简洁.
是的,两者都是相同的,它是null-coalescing运算符.
如果操作数不为null,则返回左侧操作数; 否则它返回右手操作数.
如果我们谈论效率那么
string MyName = (s.MyName == null) ? string.Empty : s.MyName;
string MyName2 = s.MyName ?? string.Empty;
Run Code Online (Sandbox Code Playgroud)
如果我使用解析器,那么我可以看到第一个语句需要19个语句由编译器执行,而第二个语句只需要执行12个语句.