Ich würde das Wort "thread safe" nicht verwenden, um sich darauf zu beziehen. Stattdessen würde ich die Frage stellen, welche von diesen ist die gleiche wie der Nullkoaleszenzoperator?
get { return _bar != null ? _bar : new Object(); }
oder
get
{
Object result = _bar;
if(result == null)
{
result = new Object();
}
return result;
}
von den anderen Antworten zu lesen, es sieht aus wie es auf den zweiten auf das Äquivalent kompiliert, nicht die erste. Wie Sie bereits angemerkt haben, könnte die erste Null zurückgeben, die zweite jedoch nie.
Ist dieses Gewinde sicher? Technisch, nein. Nach dem Lesen _bar
könnte ein anderer Thread _bar
ändern, und der Getter würde einen veralteten Wert zurückgeben. Aber von dem, wie du die Frage gestellt hast, denke ich, dass du genau das suchst.
Edit: Hier ist ein Weg, um das ganze Problem zu vermeiden. Da value
eine lokale Variable ist, kann sie nicht hinter den Kulissen geändert werden.
public class Foo
{
Object _bar = new Object();
public Object Bar
{
get { return _bar; }
set { _bar = value ?? new Object(); }
}
}
Edit 2:
Hier ist die IL ich aus einer Veröffentlichung der Kompilierung zu sehen, die mit meiner Interpretation des 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.
}
Hier ist, was ich von den anderen Möglichkeiten sehen, es zu tun:
.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
}
Im IL, ist es offensichtlich, dass es die _bar
Feld zweimal mit dem trinary Operator liest, aber nur einmal mit dem Null koaleszieren und das Zwischenergebnis var. Darüber hinaus ist die IL der Null-Koaleszenz-Methode der Zwischenergebnis-Var-Methode sehr ähnlich.
Und hier ist die Quelle, die ich diese zu erzeugen verwendet:
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(); }
}
Sie konnten die generische Faule Klasse verwenden, anstatt sicher zu initialisieren. http://msdn.microsoft.com/en-us/library/dd642331.aspx – TrueWill
@TrueWill: Es ist schwierig, Lazy zu verwenden, wenn Sie in der Lage sein müssen, einen Setter auf der Eigenschaft zu haben ... –
Gefunden: http://haacked.com/archive/2006/08/08/IsTheNullCoalescingOperatorThreadSafe.aspx –