次のコードを検討してください。
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
MethodInfo methodInfo = typeof(Program).GetMethod("Baz"); // Foo Baz(){return foo;}
Type typeFoo = methodInfo.ReturnType;
var result = (typeFoo)objFoo;
結果を得るためにtypeFoo
で魔法をかける必要がありますか?
番号 :-)
ケース1:
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
Foo result = (Foo)objFoo;
コンパイル時にFoo
型を知っているため、ここではリフレクションはありません。
ケース2:インターフェース。通常は最高のものです... MakeFoo
が何を返すのか正確にはわかりませんが、それはIFoo
インターフェースであることは知っています...
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
IFoo result = (IFoo)objFoo;
ケース3:MakeFoo
がFoo
を返すかどうかわからない
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
if (objFoo is Foo)
{
Foo result = (Foo)objFoo;
}
または類似
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
Foo foo = objFoo as Foo;
if (foo != null)
{
// use foo
}
ケース4:タイプFoo
はプログラムでは完全に不明です。参照可能なFoo
クラスがありません...
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
Type typeFoo = objFoo.GetType(); // You should check for null values before!
// and now?
dynamic foo = objFoo;
// because you know that foo can Quack(1, 2, 3)!
string result = foo.Quack(1, 2, 3);
// note that it will explode with a RuntimeBinderException if there is no
// string Quack(int, int, int) method!
dynamic
は内部的にリフレクションを使用します。リフレクションを直接使用してQuack
メソッドを取得し、それを呼び出すことができます
ケース5:ケース4と同じですが、直接反射を使用します。
object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}
Type typeFoo = objFoo.GetType(); // You should check for null values before!
MethodInfo mi = type.GetMethod("Quack"); // You should check if the Quack method
// exists
string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 });
または、いくつかの健全性チェックで、foo
がQuack
を正しく実行できるか不明な場合:
MethodInfo mi = type.GetMethod("Quack",
BindingFlags.Instance | BindingFlags.Public,
null,
new[] { typeof(int), typeof(int), typeof(int) },
null);
if (mi != null && typeof(string).IsAssignableFrom(mi.ReturnType))
{
string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 });
}
Case -Infinity:タイプFoo
は、プログラムでは完全に不明です。参照可能なFoo
クラスがありません。 IFoo
インターフェースがありません。あなたはFoo
が何であるかさえ知りません、あなたはそれがクラスであることだけを知っています(あるいはそれは箱入りのstruct
であるかもしれません、しかしそれはあなたの観点から変化しません...それはinterface
ではあり得ないので、すべてのclass
の後ろには、具体的なstruct
/interface
が常に存在する必要があります。メソッド、フィールド、プロパティがわかりません(Foo
が何であるかわからないため)。
object
をこの不明なクラスにキャストできたとしても、何ができますか?パラメータ/戻り値としてそれを受け入れるメソッドをコードに含めることはできません。
int INeedFoo(Foo par) { return 0; }
そうすれば、Foo
がわかるでしょう。 .NETライブラリには、それをパラメーター/戻り値として受け入れるメソッドを含めることはできません。それが可能であれば、Foo
を知っているからです。
あなたができる唯一のことは、パラメータとしてFoo
を受け入れるリフレクションを通じて発見した他のいくつかのメソッドにそれを渡すことです...しかし、Invoke
メソッドは、object
の配列をパラメータとして受け入れます... object
をキャストする必要はありませんInvoke
を呼び出す!配列に入れるだけです。
これは、反射型へのキャストに関するGoogleの最初の結果です。
したがって、参考までに、sbがリフレクションタイプにキャストする一般的な方法は何だろうと思う場合は、次のようにします。
public static class ObjectExtensions
{
public static T CastTo<T>(this object o) => (T)o;
public static dynamic CastToReflected(this object o, Type type)
{
var methodInfo = typeof(ObjectExtensions).GetMethod(nameof(CastTo), BindingFlags.Static | BindingFlags.Public);
var genericArguments = new[] { type };
var genericMethodInfo = methodInfo?.MakeGenericMethod(genericArguments);
return genericMethodInfo?.Invoke(null, new[] { o });
}
}
これは次と同等です。
object objFoo = MakeFoo();
Foo result = (Foo)objFoo;
コンパイル時に不明な型にオブジェクトをキャストしても、実際には意味がありません-使用できません。
object objFoo = MakeFoo();
UnkownType result = (UknownType)objFoo;
UknownType
が何であるかがわからないため、リフレクションやダイナミクスに頼らずにそのメソッドを使用することはできません。