4

Before C# 6, I would write code to dispose of an object like:

if (_odbcConnection != null)
{
    _odbcConnection.Close();
    _odbcConnection.Dispose();
    _odbcConnection = null;
}

With 6, I can write much less code:

_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;

But are the two equivalent?

4

1 回答 1

9

Your two lower examples are almost equal. But the second block

_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;

will be translated by the compiler to something like

var tmp1 = _odbcConnection;
if (tmp1 != null) tmp1.Close();
var tmp2 = _odbcConnection;
if (tmp2 != null) tmp2.Dispose();
_odbcConnection = null;

This means that this version is thread-safe, while the first (with the outer if clause) is not. If some mysterious thread would set _odbcConnection to null after the if but before Close() or Dispose(), a NullReferenceException would be thrown.

By using the null-conditional-operator you avoid this problem, because the reference is first stored in a compiler generated variable and then checked and used.


The above translation only applies to fields and properties. For local variables (only in scope of a single method, e.g. method parameters), this translation is not necessary and the code ends up like

if (_odbcConnection != null) _odbcConnection.Dispose();

That is because local variables cannot be changed by different threads.

And of course this is only the generated C#. In IL you may not see this anymore as it is either optimized away or obsolete, because in IL the reference value is loaded into a register and then compared. Again, another thread can no longer change that value in the register. So on IL level this discussion is somewhat pointless.

于 2017-02-07T15:19:01.960 回答