In variabili locali, con ottimizzazione abilitata, il compilatore si (almeno a volte) compilare in codice che prima assegna alla variabile, quindi chiama Add
(o imposta proprietà, per inizializzatori oggetto).
Se si utilizza un statico o una variabile di istanza, vedrete un comportamento diverso:
class Test
{
static List<int> StaticList = new List<int> { 1 };
List<int> InstanceList = new List<int> { 2 };
}
ha pronunciato la seguente L'inizializzatore di tipo:
.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
// Code size 21 (0x15)
.maxstack 2
.locals init (class [mscorlib]System.Collections.Generic.List`1<int32> V_0)
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.1
IL_0008: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000d: nop
IL_000e: ldloc.0
IL_000f: stsfld class [mscorlib]System.Collections.Generic.List`1<int32> Test::StaticList
IL_0014: ret
} // end of method Test::.cctor
E la seguente IL costruttore:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 29 (0x1d)
.maxstack 3
.locals init (class [mscorlib]System.Collections.Generic.List`1<int32> V_0)
IL_0000: ldarg.0
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.2
IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000e: nop
IL_000f: ldloc.0
IL_0010: stfld class [mscorlib]System.Collections.Generic.List`1<int32> Test::InstanceList
IL_0015: ldarg.0
IL_0016: call instance void [mscorlib]System.Object::.ctor()
IL_001b: nop
IL_001c: ret
} // end of method Test::.ctor
In entrambi i casi, la raccolta viene compilata prima il campo è impostato. Questo non vuol dire che potrebbero non esserci ancora problemi con il modello di memoria, ma è non uguale al campo impostato per fare riferimento a una raccolta vuota e quindi alla chiamata Add
effettuata. Dal punto di vista del thread di assegnazione, l'assegnazione avviene dopo lo Add
.
In generale, entrambe le espressioni di inizializzazione degli oggetti e la raccolta di inizializzazione sono equivalenti a costruire l'oggetto utilizzando una variabile temporanea - così nel caso in cui lo si utilizza in un incarico, il setter di proprietà sono tutti chiamati prima l'assegnazione avviene .
Tuttavia, non credo che qualsiasi garanzie speciali siano fornite in base alla visibilità di altri thread per inizializzatori di oggetti/raccolte. Ti suggerirei di immaginare come sarebbe il codice se scritto "long-hand" secondo le specifiche, e quindi la ragione da lì.
Ci sono garanzie prestate per inizializzatori statici e costruttori - ma in primo luogo all'interno l'implementazione Microsoft di .NET piuttosto che garanzie "generali" (per esempioall'interno della specifica C# o delle specifiche ECMA).
Sospetto che la risposta ad entrambe le domande sia sì in presenza di più thread, ma non capisco abbastanza bene il modello di memoria per essere sicuro. – SLaks
Valuta la possibilità di leggere http://www.amazon.com/CLR-via-Microsoft-Developer-Reference/dp/0735667454 – SLaks
Questo codice non è legale; sei sicuro di volere 'var' lì dentro? I locali non sono volatili e non hanno mai punti nel loro nome; hai intenzione di essere un campo? –