これを参照するために「スレッドセーフ」という言葉は使用しません。代わりに、次のうちどれが null 合体演算子と同じでしょうか?という質問をします。
get { return _bar != null ? _bar : new Object(); }
また
get
{
Object result = _bar;
if(result == null)
{
result = new Object();
}
return result;
}
他の応答を読むと、最初のものではなく、2番目のものと同等にコンパイルされるようです。ご指摘のとおり、最初のものは null を返す可能性がありますが、2 番目のものは決して返されません。
このスレッドは安全ですか? 技術的には、いいえ。を読み取った後_bar
、別のスレッドが を変更する可能性が_bar
あり、ゲッターは古い値を返します。しかし、あなたが質問した方法から、これがあなたが探しているものだと思います。
編集:これは、問題全体を回避する方法です。はローカル変数であるためvalue
、裏で変更することはできません。
public class Foo
{
Object _bar = new Object();
public Object Bar
{
get { return _bar; }
set { _bar = value ?? new Object(); }
}
}
編集2:
リリース コンパイルから見た 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 では、3 項演算子でフィールドを 2 回読み取っていることは明らかです_bar
が、null 合体と中間結果の var では 1 回だけです。さらに、null 合体メソッドの 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(); }
}