参照として渡す唯一の方法は、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;
}
最初に変数 myEnum を値で渡して DoSomethingByEnum を呼び出し、次に再度 myEnum を渡す DoSomethingDynamicByValue を呼び出しますが、動的型として暗黙的にボックス化されます。これは、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(dynamic) の唯一の違いは、変数 myEnum をボックス化することです (新しいオブジェクトを作成し、値の型から新しく割り当てられた動的オブジェクトにデータをコピーすることによって達成されます)。これを確認してくださいBox Opcode
DoSomethingByEnum(MyEnum) および DoSomethingDynamicByValue(dynamic) 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 dynamic) で何が起こるか見てみましょう。
メインメソッドを続行するには
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 と前の 2 つの例の違いは、次の 2 つの命令に依存してアドレスをロードおよびフェッチすることです。
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
異なるオブジェクト タイプのアドレスを渡すことができない理由は、ldloca.sとldind.refの上の 2 つの IL 命令の MSDN ページで説明されていると思います。
正しい形式の Microsoft Intermediate Language (MSIL) により、ポインタの型と一貫した方法で ldind 命令が使用されます。スタックに最初にプッシュされたアドレスは、マシン上のオブジェクトの自然なサイズに合わせる必要があります
これが少し明確になることを願っています。