xqM*_*vKW 6 c# struct idisposable using
假设我有一个实现IDisposible的结构类型,如果我使用下面的代码:
using (MyStruct ms = new MyStruct())
{
InnerAction(ms); //Notice "InnerAction" is "InnerAction(MyStruct ms)"
}
Run Code Online (Sandbox Code Playgroud)
当然我看到在使用块之后,ms被处理掉了.然而,"InnerAction"中的结构呢?它是否仍然存在,因为深层复制或它也处置?
如果它仍然存活(未处理),我必须使用"ref"作为"InnerAction"吗?
请给我你的证明:)
大家好.
这比你想象的更糟糕:ms甚至没有被处置。
原因是该using语句创建了一个内部副本,并在 try/finally 构造中调用了 dispose。
考虑这个LinqPad 示例:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是一些反编译的 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
Run Code Online (Sandbox Code Playgroud)
请注意,在 IL_000E 中,创建了编译器生成的 local ( ) 并在那里存储了CS$3$0001的副本。ms之后...
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
Run Code Online (Sandbox Code Playgroud)
Dispose针对此本地调用,而不是ms(存储在位置 0 中)。
结果是两者ms和保留的副本InnerAction都没有被处理。
结论:不要在using语句中使用结构。
编辑:正如@Weston在评论中指出的那样,您可以手动装箱结构并对装箱的实例进行操作,因为它随后位于堆上。通过这种方式,您可以释放实例,但如果您将其强制转换回语句中的结构using,则最终只会在释放实例之前存储一个副本。此外,拳击消除了远离堆的好处,而您可能已经做到了这一点。
MyStruct ms = new MyStruct();
var disposable = (IDisposable)ms;
using (disposable)
{
InnerAction(disposable);
}
((MyStruct)disposable).IsDisposed.Dump();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
140 次 |
| 最近记录: |