我不会使用“线程安全”这个词来指代这一点。相反,我会问一个问题,其中哪一个与空合并运算符相同?
get { return _bar != null ? _bar : new Object(); }
或者
get
{
Object result = _bar;
if(result == null)
{
result = new Object();
}
return result;
}
从阅读其他回复来看,它似乎编译为第二个,而不是第一个。正如您所指出的,第一个可以返回 null,但第二个永远不会。
这个线程安全吗?从技术上讲,没有。阅读后_bar
,不同的线程可以修改_bar
,getter 将返回一个过时的值。但从你问这个问题的方式来看,我认为这就是你要找的。
编辑:这是一种避免整个问题的方法。由于value
是局部变量,因此无法在后台更改。
public class Foo
{
Object _bar = new Object();
public Object Bar
{
get { return _bar; }
set { _bar = value ?? new Object(); }
}
}
编辑2:
这是我从 Release 编译中看到的 IL,以及我对 IL 的解释。
.method public hidebysig specialname instance object get_Bar_NullCoalesce() cil managed
{
.maxstack 8
L_0000: ldarg.0 // Load argument 0 onto the stack (I don't know what argument 0 is, I don't understand this statement.)
L_0001: ldfld object CoalesceTest::_bar // Loads the reference to _bar onto the stack.
L_0006: dup // duplicate the value on the stack.
L_0007: brtrue.s L_000f // Jump to L_000f if the value on the stack is non-zero.
// I believe this consumes the value on the top of the stack, leaving the original result of ldfld as the only thing on the stack.
L_0009: pop // remove the result of ldfld from the stack.
L_000a: newobj instance void [mscorlib]System.Object::.ctor()
// create a new object, put a reference to it on the stack.
L_000f: ret // return whatever's on the top of the stack.
}
这是我从其他方法中看到的:
.method public hidebysig specialname instance object get_Bar_IntermediateResultVar() cil managed
{
.maxstack 1
.locals init (
[0] object result)
L_0000: ldarg.0
L_0001: ldfld object CoalesceTest::_bar
L_0006: stloc.0
L_0007: ldloc.0
L_0008: brtrue.s L_0010
L_000a: newobj instance void [mscorlib]System.Object::.ctor()
L_000f: stloc.0
L_0010: ldloc.0
L_0011: ret
}
.method public hidebysig specialname instance object get_Bar_TrinaryOperator() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld object CoalesceTest::_bar
L_0006: brtrue.s L_000e
L_0008: newobj instance void [mscorlib]System.Object::.ctor()
L_000d: ret
L_000e: ldarg.0
L_000f: ldfld object CoalesceTest::_bar
L_0014: ret
}
在 IL 中,很明显,它_bar
使用三元运算符读取了两次字段,但只有一次使用 null 合并和中间结果 var。此外,null coalesce 方法的 IL 非常接近于中间结果 var 方法。
这是我用来生成这些的来源:
public object Bar_NullCoalesce
{
get { return this._bar ?? new Object(); }
}
public object Bar_IntermediateResultVar
{
get
{
object result = this._bar;
if (result == null) { result = new Object(); }
return result;
}
}
public object Bar_TrinaryOperator
{
get { return this._bar != null ? this._bar : new Object(); }
}