C# How to Initialize Generic class with object of type "Type"
Asked Answered
Y

2

6

I recently had this problem.

doSomething(typeof(int));
doSomething(typeof(MyClassA));
doSomething(typeof(MyClassB));

public void doSomething(Type _type)
{
    var myGenObj = new MyGenericClass<_type>();  // Error.  Really I'd want MyGenericClass<int>, MyGenericClass<MyClassA>, etc depending on what's passed in.
    myGenObj.doSomeGenStuff();
    // more stuff...

}

I think that this can be done with reflection somehow.. Possibly there's an easier way. I've been somewhat confused on how Type works vs Classes under the covers. Anyways thanks for any help.

Thanks.

Yellowlegs answered 27/9, 2013 at 20:10 Comment(0)
T
13

You want Type.MakeGenericType and then Activator.CreateInstance... but then calling a method on the newly-created object will be tricky. Ideally you could have a non-generic base class or interface containing those members:

public interface IFoo
{
    void CallSomeMethod();
}

public class MyGenericClass<T> : IFoo
{
    ...
}

// Names changed to be more conventional
public void DoSomething(Type type)
{
    var genericType = typeof(MyGenericClass<>).MakeGenericType(type);
    var instance = (IFoo) Activator.CreateInstance(genericType);
    instance.CallSomeMethod();
}

If you do need to call a method which depends on the type parameter, you'll need to do that with reflection, or with dynamic which can streamline reflection-based code.

EDIT: As cdhowie says, if you always actually do know the type at compile-time, you can use a generic method which would make things much simpler. You'd then call the method like this:

DoSomething<int>();
DoSomething<MyClassA>();
DoSomething<MyClassB>();
Theresa answered 27/9, 2013 at 20:14 Comment(3)
Thanks, Thought there was a cleaner solution but I guess not.Yellowlegs
@RayL: No, generics are tricky with reflection - they're basically designed for when the type arguments are known at compile-time.Theresa
@RayL: Read cdhowie's answer as well - all the samples you've given are where the type argument is known at compile-time. Is that actually the case? If so, use a generic method.Theresa
S
5

Like this:

object myGenObj = Activator.CreateInstance(typeof(MyGenericClass<>).MakeGenericType(_type));

However, since the produced object is of a type that you don't know at compile-time, you can't really invoke members of the object through the generic type (except via reflection). If there is an ancestor type or implemented interface that you do know of at compile-time, you can cast to that and then invoke the member.

You might also consider wrapping this functionality in a generic method, which makes the whole thing easier to deal with:

public void doSomething<T>()
{
    var myGenObj = new MyGenericClass<T>();
    myGenObj.doSomeGenStuff();
}

If you have to support Type objects you can use an overload that cheats using reflection:

public void doSomething(Type _type)
{
    this.GetType().GetMethod("doSomething", Type.EmptyTypes)
        .MakeGenericMethod(_type)
        .Invoke(this, null);
}
Sweat answered 27/9, 2013 at 20:14 Comment(1)
Thanks, Wasn't sure who to mark as answer on this one but people seemed to like skeets answer a bit more. Sorry you had to compete with him :)Yellowlegs

© 2022 - 2024 — McMap. All rights reserved.