私はこれがボンネットの下で起こっていると思いますFoo((dynamic)a)
:
Asset a = new House();
Type t = typeof(MainClass);
t.InvokeMember("Foo",
System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { a });
それは解決しますFoo(House h)
リフレクション (例: InvokeMember) を使用せずに monodis.exe に簡単に移動します。つまり、代わりに dynamic キーワードを使用しますAsset a = new House(); Foo((dynamic)a)
。これが IL です。
IL_0025: ldstr "Foo"
IL_002a: ldnull
IL_002b: ldtoken MainClass
IL_0030: call class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
「Foo」は、ダイナミクスがリフレクションのような種類のビジネスであるという死んだ景品です。
さて、これは動的ではありません。つまり、次のようになりAsset a = new House(); Foo(a)
ます。
IL_0010: ldloc.0
IL_0011: call void class MainClass::Foo(class Asset)
焼かれた命令はほぼ決定され、変更されず、常に解決されますFoo(Asset);
(monodis.exe または ildasm.exe を介して) 動的動作を分析するために使用できる完全なコードを次に示します。
using System;
public class MainClass {
public static void Main() {
Console.WriteLine("Hei");
Asset a = new House();
Foo(a);
Foo((dynamic)a);
object x = 7;
Foo((dynamic)x);
}
public static void Foo(House h) { Console.WriteLine("House"); }
public static void Foo(Asset a) { Console.WriteLine("Asset"); }
public static void Foo(int i) { Console.WriteLine("int"); }
}
public class Asset {
}
public class House : Asset {
}
出力:
Hei
Asset
House
int
これにより、Foo オーバーロード int が呼び出されます。つまり、次のようになりFoo(int i)
ます。
object x = 7;
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { x } );
これも次のようになります。
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { 8 } );
あなたの質問では、他にどのようなオプションを使用できますか。型指定されていないオブジェクトを受け入れるメソッドを使用できます。
public static void FooDynamic(object o)
{
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { o } );
}
呼び出す:
Asset a = new House();
FooDynamic(a); // will select Foo House overload
int i = 7;
FooDynamic(i); // will select Foo int overload
上記のコードにこの API を使用することもできます:public static void Foo(object o)
の場合、次のように Foo を呼び出す必要があります。
Asset a = new House();
Foo((object)a); // will resolve to House
C# 4 には既にdynamic
機能があることを考えると、開発者がまだ C# 3 を使用していない限り、リフレクションを使用するのは難しいでしょう。そのため、代わりに動的アプローチを使用してください :-)
アップデート
このコードを実行すると、文字「B」が表示されるまでに約 2 秒のかなりの遅延がありますdynamic
。ダイナミックとリフレクションのコード順序を入れ替えても、ダイナミックの遅延は再現可能です。リフレクションの遅延は感知できず、動的よりも高速です。
using System;
public class MainClass {
public static void Main() {
// there's a delay on initial dynamic call, about two seconds
Test ();
Console.ReadLine ();
// dynamic's speed is instant on subsequent calls,
// as clarified by Eric Lippert, the delegate is cached,
// hence the elimination of delay on subsequent dynamic calls
Test ();
}
public static void Test() {
Asset a = new House();
Console.WriteLine("A");
Foo((dynamic)a); // there is a considerable delay here, the "B" string appears after two seconds
Console.WriteLine ("B");
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { a } );
Console.WriteLine("C");
}
public static void Foo(House h) { Console.WriteLine("House"); }
public static void Foo(Asset a) { Console.WriteLine("Asset"); }
public static void Foo(int i) { Console.WriteLine("int"); }
}
public class Asset {
}
public class House : Asset {
}