Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast to a reflected Type in C#

Tags:

Consider the following code:

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; 

Do I need to do some magic with typeFoo to get the result?

like image 662
user2341923 Avatar asked Aug 05 '13 07:08

user2341923


1 Answers

No :-)

Case 1:

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} Foo result = (Foo)objFoo; 

There is no reflection here, because you know the Foo type at compile time.

Case 2: interfaces. Normally the best one... You don't know what exactly MakeFoo returns, but you know it's an IFoo interface...

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} IFoo result = (IFoo)objFoo; 

Case 3: you aren't sure MakeFoo returns Foo

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}  if (objFoo is Foo) {     Foo result = (Foo)objFoo; } 

or, similar

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();}  Foo foo = objFoo as Foo;  if (foo != null) {     // use foo } 

Case 4: type Foo is completely unknown to your program. You don't have a Foo class referenceable...

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! 

the dynamic internally uses reflection. You could use reflection directly to get the Quack method and call it

Case 5: as case 4, but using directly reflection:

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 }); 

or, with some sanity checks, if you aren't sure foo can Quack correctly:

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: type Foo is completely unknown to your program. You don't have a Foo class referenceable. You don't have an IFoo interface. You don't even know what a Foo is, you know only that it's a class (or perhaps it's a boxed struct, but it doesn't change from your point of view... It can't be an interface because in the end there must always be a concrete class/struct behind every interface). You don't know of its methods, its fields, its properties (because you don't know what Foo is).

Even if you can cast an object to this unknown class, what can you do? You can't have methods in your code that accept it as a parameter/return value, because if somewhere you had:

int INeedFoo(Foo par) { return 0; } 

then clearly you would know of Foo. The .NET library can't have methods that accept it as a parameter/return value, because if it had, you would know of Foo.

The only thing you can do is pass it to some other methods that you discover through reflection that accept Foo as a parameter... But the Invoke method accepts an array of object as parameters... You don't need to cast your object to call Invoke! You only need to put it in the array.

like image 140
xanatos Avatar answered Oct 07 '22 08:10

xanatos