views:

125

answers:

7

Hello all! I'm trying to create an instance of a generic class using a Type object.

Basically, I'll have a collection of objects of varying types at runtime, and since there's no way for sure to know what types they exactly will be, I'm thinking that I'll have to use Reflection.

I was working on something like:

Type elType = Type.GetType(obj);
Type genType = typeof(GenericType<>).MakeGenericType(elType);
object obj = Activator.CreateInstance(genType);

Which is well and good. ^_^

The problem is, I'd like to access a method of my GenericType<> instance, which I can't because it's typed as an object class. I can't find a way to cast it obj into the specific GenericType<>, because that was the problem in the first place (i.e., I just can't put in something like:)

((GenericType<elType>)obj).MyMethod();

How should one go about tackling this problem?

Many thanks! ^_^

+3  A: 

In C# 3.5 you have to use Type.GetMethod and MethodInfo.Invoke to call the method.

In C# 4 you can use the dynamic keyword and bind to the method at runtime.

Randolpho
+5  A: 

You would have to continue using Reflection to invoke the actual method:

// Your code
Type elType = Type.GetType(obj);
Type genType = typeof(GenericType<>).MakeGenericType(elType);
object obj = Activator.CreateInstance(genType);

// To execute the method
MethodInfo method = genType.GetMethod("MyMethod",
    BindingFlags.Instance | BindingFlags.Public);
method.Invoke(obj, null);

For more information see Type.GetMethod and MethodBase.Invoke.

Aaronaught
I was actually thinking that, and thought that maybe (*just maybe*) there was a way around it. No such luck, I guess. :)Thanks!
Richard Neil Ilagan
@Richard Neil Ilagan: Well... there is *some* luck. Next month (ish) Microsoft releases VS 2010 and .NET 4. When that happens you will be able to do exactly what you want wrote in your question; the `dynamic` keyword I mentioned in my answer will bind to the method at runtime rather than compiletime (which means you'll get an exception at runtime if the method doesn't exist, rather than a compiler error). You can fool around with .NET 4 for free *now* using the release candiate of VS2010.
Randolpho
Maybe you'll also find Fasterflect (http://fasterflect.codeplex.com) to be of interest. It's a library designed to make reflection easier to use and faster through code generation. Lets you do neat things like invoking the best overload match given a set of parameters as well as more basic stuff.
Morten Mertner
@Randolpho ~ yeap! I'm actually a bit excited about that aspect of .NET4 as well. Here's to hoping that we're able to migrate our apps right from the get-go though! :)@Morten ~ thanks a lot! That will definitely make my lib of helper code. :)
Richard Neil Ilagan
+3  A: 

Once you start the reflection game you have to play it till the end. The type is not known at compile time, so you cannot cast it. You'll have to invoke the method by reflection:

obj.GetType().InvokeMember(
    "MyMethod", 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, 
    null, 
    obj, 
    null
);
Darin Dimitrov
+1. Love that first line. Ya gotta play the game all the way to the end, man. *edit* Also, I just lost the game.
Randolpho
I have to agree: that first line's a killer. I was afraid of that. Hahaha! :D
Richard Neil Ilagan
+1  A: 

Once you've created the instance, just do:

MethodInfo method = genType.GetMethod("MyMethod");
method.Invoke(obj, null);
Reed Copsey
+2  A: 

The most straightforward approach is to extract a non-generic supertype (either base class or interface) from GenericType that contains the methods you want to expose for this purpose:

class GenericType<T> : GenericBase { ... }
class GenericBase { abstract void MyMethod(); }

Failing that, use reflection to access the method itself as suggested by @Aaronaught.

Jeffrey Hantin
A: 

If you know the signature of the methods you want to invoke, you can not only use MethodInfo.Invoke() as shown in other samples here but also create a delegate which allows for more efficient invocation (if you need to invoke the same method several times) using Delegate.CreateDelegate().

Lucero
A: 

I'm not sure how much your types vary or if you have control over the methods that you'll be calling in them, but it might be useful to create an interface that defines which set of functions you're going to be calling. So after creating the instance, you can cast to the interface and call whatever functions you need.

so create your standard interface (which you'll need to implement in each type, if you have control over them):

interface IMyInterface
{
   void A();
   int  B();
}

class One : IMyInterface
{
   ...
   implement A and B
   ...
}

Type elType = Type.GetType(obj);
Type genType = typeof(GenericType<>).MakeGenericType(elType);
IMyInterface obj = (IMyInterface)Activator.CreateInstance(genType);
obj.A();
Mark Synowiec