È peggio di quanto si pensi: ms
non è nemmeno smaltito.
Il motivo è che l'istruzione using
crea una copia interna che chiama dispose in un costrutto try/finally.
Considerate questo LinqPad example:
void Main()
{
MyStruct ms;
using (ms = new MyStruct())
{
InnerAction(ms);
}
ms.IsDisposed.Dump();
_naughtyCachedStruct.IsDisposed.Dump();
}
MyStruct _naughtyCachedStruct;
void InnerAction(MyStruct s)
{
_naughtyCachedStruct = s;
}
struct MyStruct : IDisposable
{
public Boolean IsDisposed { get; set; }
public void Dispose()
{
IsDisposed = true;
}
}
Ecco alcuni dei IL decompilato:
IL_0000: nop
IL_0001: ldloca.s 01 // CS$0$0000
IL_0003: initobj UserQuery.MyStruct
IL_0009: ldloc.1 // CS$0$0000
IL_000A: dup
IL_000B: stloc.0 // ms
IL_000C: dup
IL_000D: stloc.0 // ms
IL_000E: stloc.2 // CS$3$0001
IL_000F: nop
IL_0010: ldarg.0
IL_0011: ldloc.0 // ms
Si noti che in IL_000E un compilatore generato locale (CS$3$0001
) viene creato e una copia del ms
viene memorizzato anche lì . Più tardi ...
IL_001B: ldloca.s 02 // CS$3$0001
IL_001D: constrained. UserQuery.MyStruct
IL_0023: callvirt System.IDisposable.Dispose
IL_0028: nop
IL_0029: endfinally
Dispose
è chiamato contro questo locale, non ms
(che è memorizzato nella posizione 0).
Il risultato è che sia lo ms
sia la copia su cui si trova lo InnerAction
non sono stati eliminati.
Conclusione: non utilizzare le strutture nelle istruzioni using
.
MODIFICA: come @Weston fa notare nei commenti, you can manually box the struct and act on the boxed instance, poiché sopravvive sull'heap. In questo modo è possibile ottenere l'istanza da smaltire, ma se è stata restituita alla struct nell'istruzione using
, si finirà per archiviare una copia prima che l'istanza sia stata eliminata. Inoltre, il pugilato rimuove il vantaggio di rimanere fuori dal mucchio, che presumibilmente fino a qui.
MyStruct ms = new MyStruct();
var disposable = (IDisposable)ms;
using (disposable)
{
InnerAction(disposable);
}
((MyStruct)disposable).IsDisposed.Dump();
Non c'è alcuna "copia profonda" e quindi non è rimasto nulla da smaltire. – Henrik
I tipi di struttura 'IDisposable' sono [una cattiva idea] (http://ericlippert.com/2011/03/14/to-box-or-not-to-box/) ... – xanatos
Le strutture mutevoli sono [un brutto idea] (http://stackoverflow.com/questions/441309/why-are-mutable-struct-evil) Per implementare i suggerimenti usa e getta deve avere uno stato, quindi deve essere modificabile. – weston