Jest gorszy niż myślisz: ms
nie jest nawet utylizowany.
Powód jest taki, że instrukcja using
tworzy wewnętrzną kopię, którą wywołuje w konstrukcie try/finally.
Rozważ to 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;
}
}
Oto niektóre z decompiled IL:
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
Zauważ, że w IL_000E kompilator generowane lokalny (CS$3$0001
) jest tworzony i kopia ms
jest tam przechowywana . Później ...
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
nazywa się przed tym lokalnym, nie ms
(który jest przechowywany w lokalizacji 0).
Powoduje to, że zarówno ms
, jak i kopia, która zatrzymuje się na kopii, nie są ułożone.
Wniosek: nie używaj struktur w instrukcjach using
.
EDYCJA: jak @Weston wskazuje w komentarzach, you can manually box the struct and act on the boxed instance, ponieważ wtedy żyje na stercie. W ten sposób możesz pobrać instancję, ale jeśli ją odrzucisz do struktury w oświadczeniu using
, skończy się przechowywanie kopii przed jej usunięciem. Co więcej, boks usuwa korzyści z pozostawania poza stosem, co prawdopodobnie należy do tej pory.
MyStruct ms = new MyStruct();
var disposable = (IDisposable)ms;
using (disposable)
{
InnerAction(disposable);
}
((MyStruct)disposable).IsDisposed.Dump();
Nie ma "głębokiej kopii" i dlatego nic nie zostało do dyspozycji. – Henrik
Typy 'IDisposable' to [zły pomysł] (http://ericlippert.com/2011/03/14/to-box-or-not-to-box/) ... – xanatos
Zmienne struktury są złe idea] (http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil) Aby implementować sugestie jednorazowe muszą mieć stan, a więc muszą być zmienne. – weston