作为参考传递的唯一方法是将myEnum转换为动态类型,然后通过引用传递它。我认为我们应该仔细研究生成的IL,以了解底层发生了什么。让我们发现为什么和分析此程序:
enum MyEnum{
A,B
}
void Main()
{
MyEnum myEnum = MyEnum.B; //Assign a variable
DoSomethingByEnum(myEnum); //Pass myEnum
DoSomethingDynamicByValue(myEnum); //pass myEnum to a dynamic parameter
dynamic dyn = myEnum; //assign myenum to a dynamic variable
DoSomethingDynamicByRef(ref dyn); //pass it as a reference
}
MyEnum DoSomethingByEnum(MyEnum a)
{
return a;
}
dynamic DoSomethingDynamicByValue(dynamic inputObject)
{
return inputObject;
}
dynamic DoSomethingDynamicByRef(ref dynamic inputObject)
{
return inputObject;
}
首先我们调用DoSomethingByEnum按值传递变量myEnum然后DoSomethingDynamicByValue再次通过myEnum但隐含盒装作为一个动态类型。这是在MSIL水平会发生什么:
Main:
IL_0001: ldc.i4.1 // MyEnum myEnum = MyEnum.B;
IL_0002: stloc.0 // myEnum popped from evaluation stack and stored in a local variable
IL_0003: ldarg.0
IL_0004: ldloc.0 // myEnum loaded from local variable at index 0 and passed to the function
IL_0005: call DoSomethingByEnum
IL_000A: pop
IL_000B: ldarg.0
IL_000C: ldloc.0 // myEnum
IL_000D: box MyEnum // dynamic dyn = myEnum;
// myEnum Converted from value type to a true object reference of type dynamic
IL_0012: call DoSomethingDynamicByValue
DoSomethingByEnum(MyEnum)和DoSomethingDynamicByValue(动态)是拳击可变myEnum(通过从值类型创建一个新对象并复制数据到完成之间的唯一区别新分配的动态对象)。检查了这一点Box Opcode
让我们看看到DoSomethingByEnum(MyEnum)和DoSomethingDynamicByValue(动态)IL:
DoSomethingDynamicByValue:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
DoSomethingByEnum:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
两种功能的IL代码是完全一样的,不管变量的类型。我们甚至可以拥有任何对象类型,但变量在调用中传递和共享的方式不会改变。
让我们来看看在DoSomethingDynamicByRef(ref动态)中会发生什么。
要继续的主要方法
Main:
IL_0018: ldloc.0 // myEnum
IL_0019: box UserQuery.MyEnum
IL_001E: stloc.1 // dyn
IL_001F: ldarg.0
IL_0020: ldloca.s 01 // loads the address of dyn onto the stack
IL_0022: call UserQuery.DoSomethingDynamicByRef
DoSomethingDynamicByRef:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldind.ref //
IL_0003: stloc.0
IL_0004: br.s IL_0006
IL_0006: ldloc.0
IL_0007: ret
这个IL最后两个例子之间的差别依赖于这两个指令来加载和取地址:
ldloca.s 01 // loads the address of dyn onto the stack
ldind.ref // Loads the object reference at address addr onto the stack as a type O
我觉得在两个IL指令的MSDN页面上面解释了为什么不可能传递不同对象类型的地址的原因:ldloca.s和ldind.ref
正确形成的微软中间语言(MSIL)确保lind指令的使用方式与指针的类型 一致。地址最初压入堆栈必须 对准对象的自然尺寸在机器上
希望这可以澄清一点。
可能[this](http://stackoverflow.com/q/2475310/335858)有关系吗? – dasblinkenlight 2013-03-23 01:02:07
好吧,如果你想知道枚举是否特殊,你可以用非枚举类型来尝试它,比如int,string或object。试试看看会发生什么。你能弄清楚这种模式吗?一旦你找出枚举是否特殊,考虑你可以用ref变量做的所有事情。有没有什么方法可以违反类型安全? – 2013-03-23 02:40:58