如果我的struct实现了IDisposable,那么当在using语句中使用时它会被装箱吗?
谢谢
编辑:这个timedlock是一个结构并实现Idisposable. http://www.interact-sw.co.uk/iangblog/2004/04/26/yetmoretimedlocking
编辑2:看看IL似乎如果你的结构公开Dispose()为public,当你忘记调用Dispose()时,编译器会在结构的一个实例超出范围时调用Dispose(例如,你没有使用"使用"声明)?
kd7*_*kd7 28
Per Eric Lippert:
对结构上的IDisposable.Dispose的调用生成为受约束的虚拟调用,大多数情况下不会对该值进行封装.
如果虚拟方法未由类型实现,则对值类型的受约束虚拟调用仅会对值进行设置.可以通过值类型实现虚拟方法的唯一情况是,该方法是ToString,并由基类System.ValueType实现.
有关更多详细信息,请参阅CLI文档的第III部分2.1.
Eri*_*ert 23
这是一个复制的什么时候一个using语句框的参数,当它是一个结构?
更新:这个问题是我2011年3月的博客主题.谢谢你提出的好问题.
几点:
((IDisposable)resource).Dispose(); 是拳击转换.我们实际上并没有生成拳击转换.因为大部分时间这都是你想要的,我们不会失去任何睡眠.Sam*_*eff 12
不,它没有盒装.
using不是方法调用.它是语法糖,编译器只是将其转换为:
MyClass m = new MyClass()
try
{
// ...
}
finally
{
if (m != null) {
m.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
它从不IDisposable在声明中使用,也从不将实例传递给其他任何东西.对于结构体,编译器实际上生成了更小的东西:
MyStruct m = new MyStruct()
try
{
// ...
}
finally
{
m.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
由于结构不能为null.
现在,要100%确定它从不装箱,看看IL.
试试这个示例代码:
class StructBox
{
public static void Test()
{
using(MyStruct m = new MyStruct())
{
}
MyStruct m2 = new MyStruct();
DisposeSomething(m2);
}
public static void DisposeSomething(IDisposable disposable)
{
if (disposable != null)
{
disposable.Dispose();
}
}
private struct MyStruct : IDisposable
{
public void Dispose()
{
// just kidding
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后看看IL:
.method public hidebysig static void Test() cil managed
{
.maxstack 1
.locals init (
[0] valuetype ConsoleApplication1.StructBox/MyStruct m,
[1] valuetype ConsoleApplication1.StructBox/MyStruct m2)
L_0000: ldloca.s m
L_0002: initobj ConsoleApplication1.StructBox/MyStruct
L_0008: leave.s L_0018
L_000a: ldloca.s m
L_000c: constrained ConsoleApplication1.StructBox/MyStruct
L_0012: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_0017: endfinally
L_0018: ldloca.s m2
L_001a: initobj ConsoleApplication1.StructBox/MyStruct
L_0020: ldloc.1
L_0021: box ConsoleApplication1.StructBox/MyStruct
L_0026: call void ConsoleApplication1.StructBox::DisposeSomething(class [mscorlib]System.IDisposable)
L_002b: ret
.try L_0008 to L_000a finally handler L_000a to L_0018
}
Run Code Online (Sandbox Code Playgroud)
行L_0000到L_0017表示m声明和using.没有拳击.
行L_0018到L_0026表示m2声明和调用DisposeSomething.见L_0021 box.
这不会打包(让我感到惊讶).我认为bnkdev的解释涵盖了它.这是我如何证明它:
在下面写了快速控制台应用程序(注意,我包括了BoxTest(),我知道它会打包,所以我有东西可以比较).
然后我使用Reflector将编译后的输出反汇编为IL(你可以使用ILDASM).
namespace StructInterfaceBoxingTest
{
public struct TestStruct : IDisposable
{
#region IDisposable Members
public void Dispose()
{
System.Console.WriteLine("Boo!");
}
#endregion
}
class Program
{
static void Main(string[] args)
{
using (TestStruct str = new TestStruct())
{
}
}
static void BoxTest()
{
TestStruct str = new TestStruct();
ThisWillBox(str);
}
static void ThisWillBox(object item) {}
}
}
好的,首先,这是IL for BoxTest - 注意L_000a线上的方框说明(astersik强调我的)
.method private hidebysig static void BoxTest() cil managed
{
.maxstack 1
.locals init (
[0] valuetype StructInterfaceBoxingTest.TestStruct str)
L_0000: nop
L_0001: ldloca.s str
L_0003: initobj StructInterfaceBoxingTest.TestStruct
L_0009: ldloc.0
L_000a: **box** StructInterfaceBoxingTest.TestStruct
L_000f: call void StructInterfaceBoxingTest.Program::ThisWillBox(object)
L_0014: nop
L_0015: ret
}
现在看看Main(我们使用带有IDisposable结构的using语句):
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] valuetype StructInterfaceBoxingTest.TestStruct str)
L_0000: nop
L_0001: ldloca.s str
L_0003: initobj StructInterfaceBoxingTest.TestStruct
L_0009: nop
L_000a: nop
L_000b: leave.s L_001c
L_000d: ldloca.s str
L_000f: constrained StructInterfaceBoxingTest.TestStruct
L_0015: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_001a: nop
L_001b: endfinally
L_001c: nop
L_001d: ret
.try L_0009 to L_000d finally handler L_000d to L_001c
}
请注意L_000f行上的约束关键字.我找不到该关键字究竟是什么意思的参考,但是如果你读过bnkdev的帖子,我认为这是正在描述的受约束的虚拟调用.
| 归档时间: |
|
| 查看次数: |
5840 次 |
| 最近记录: |