The*_*der 2 c# c#-6.0 null-conditional-operator
在C#6之前,我会编写代码来处理像这样的对象:
if (_odbcConnection != null)
{
_odbcConnection.Close();
_odbcConnection.Dispose();
_odbcConnection = null;
}
Run Code Online (Sandbox Code Playgroud)
有了6,我可以编写更少的代码:
_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;
Run Code Online (Sandbox Code Playgroud)
但这两个是等价的吗?
你的两个较低的例子几乎是相同的.但第二块
_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;
Run Code Online (Sandbox Code Playgroud)
将由编译器翻译成类似的东西
var tmp1 = _odbcConnection;
if (tmp1 != null) tmp1.Close();
var tmp2 = _odbcConnection;
if (tmp2 != null) tmp2.Dispose();
_odbcConnection = null;
Run Code Online (Sandbox Code Playgroud)
这意味着此版本是线程安全的,而第一个(使用外部if子句)则不是.如果某种神秘的线程将设置_odbcConnection于null后if,但之前Close()还是Dispose(),一个NullReferenceException会被抛出.
通过使用null-conditional-operator,可以避免此问题,因为引用首先存储在编译器生成的变量中,然后进行检查和使用.
以上翻译仅适用于字段和属性.对于局部变量(仅在单个方法的范围内,例如方法参数),此转换不是必需的,代码最终会像
if (_odbcConnection != null) _odbcConnection.Dispose();
Run Code Online (Sandbox Code Playgroud)
这是因为不同的线程不能改变局部变量.
当然这只是生成的C#.在IL中,您可能不会再看到它,因为它被优化掉或过时,因为在IL中,参考值被加载到寄存器中然后进行比较.同样,另一个线程不能再在寄存器中更改该值.所以在IL级别上,这种讨论有点毫无意义.