3

I have a generic class that has a generic method that uses the same type as the type passed when instantiating the object. At runtime, I will only know the name of the object I need to pass in by a string representation of that object name. I've read a few things about using Activator and possibly using dynamic but I can't wrap my head around how I need to make this work. Here's a snippet of what my generic class looks like:

public class MyClass<T> where T : class, new()
{ 
        public IList<T> MyMethod(Stream stream)
        {
             var data = new List<T>();
             // stuff to create my list of objects
             return data;
        }
}

I need to return my IList from the MyMethod() method based on the name of the object I'm passing in as a string.

I could just do a switch/case on the string and then instantiate the MyClass within the case with the reference to the "real" object, but I'm wondering if there's a better (shorter and cleaner) way of doing this.

TIA

3
  • Can you clarify - it sounds like you're saying that the type of the item is T but then the type comes from a string. Commented May 18, 2016 at 18:26
  • I'm guessing you want something where you're instantiating the generic type by passing the name of the class as a string.. and from that string you want to declare your generic IList<>... correct? Commented May 18, 2016 at 18:31
  • that's exactly right. I am going to be getting my Model name (T) from a string value from a database. So I need to be able to create my MyClass object and call the MyMethod method on that instance of my object by passing in T which I will have to generate from a string representation of the model name. See the comment I made on jgauffin's answer for more clarification. Commented May 18, 2016 at 18:33

3 Answers 3

10

Your wrapper got the following signature:

public class MyClass<T> where T : class, new()

it basically says "T needs to be a class and have a default constructor". The interesting part is about the default constructor. It means that the class must have a constructor with no arguments.

It tells .NET that you can invoke:

var obj = new T();

So the first step is to do just that:

public class MyClass<T> where T : class, new()
{ 
        public IList<T> MyMethod(Stream stream)
        {
             var data = new List<T>();

             //this
             var obj = new T();

             return data;
        }
}

next you wanted to invoke a method. That's done with the help of reflection.

A simple example is:

var obj = new T();

//get type information
var type = obj.GetType();

//find a public method named "DoStuff"
var method = type.GetMethod("DoStuff");

// It got one argument which is a string.
// .. so invoke instance **obj** with a string argument
method.Invoke(obj, new object[]{"a string argument"});

Update

I missed the important part:

I need to return my IList from the MyMethod() method based on the name of the object I'm passing in as a string.

If the type is declared in the same assembly as your executing code you can just pass the full type name like Some.Namespace.ClassName" toType.GetType()`:

var type = Type.GetType("Some.Namespace.ClassName");
var obj = Activator.CreateInstance(type);

If the class is declared in another assembly you need to specify it:

var type = Type.GetType("Some.Namespace.ClassName, SomeAsseblyName");
var obj = Activator.CreateInstance(type);

The rest is pretty much the same.

If you only have the class name you can traverse the assembly to find the correct type:

var type = Assembly.GetExecutingAssembly()
                   .GetTypes()
                   .FirstOrDefault(x => x.Name == "YourName");
var obj = Activator.CreateInstance(type);
Sign up to request clarification or add additional context in comments.

3 Comments

I guess I didn't explain my problem well enough. I have the method returning exactly what I need when I hard code the model type, ex: var myObject = new MyClass<MyModel>(); then IList<MyModel> data = myObject.MyMethod(someStream); What I need is to be able to make this dynamic for any model type. IE, I won't know the type of the model (MyModel above) until runtime at which point I'll only know it by the name of the model as a string. So I could have "MyModel" or "MyModel2" etc and I need to create an instance of MyClass where I only know T as a string.
thanks for the update jgauffin. I'm trying this now: var cs = new MyClass<obj>(); where obj is being set from Activator.CreateInstance(type) and VS is barking at me. I think because I just need to pass the "type" in, not an instance of the object.
you can't use type constraints (T) if you do not know what kind of object it is at compile time . Change to a list of object instead.
3

It sounds like you want to create the generic type so that you can create an instance of it.

//Assuming "typeName" is a string defining the generic parameter for the
//type you want to create.
var genericTypeArgument = Type.GetType(typeName);
var genericType = typeof (MyGenericType<>).MakeGenericType(genericTypeArgument);
var instance = Activator.CreateInstance(genericType);

This assumes that you already know what the generic type is, but not the type argument for that generic type. In other words, you're trying to determine what the <T> is.

1 Comment

Beat me to it - but this was going to be my exact answer.
1

Use Reflection. Make MyMethod static. See the code below:

public object run(string typename, Stream stream)
{
        var ttype = Assembly
             .GetExecutingAssembly()
             .GetTypes()
             .FirstOrDefault(x => x.Name == typename);
        MethodInfo minfo = typeof(MyClass)
             .GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);
        return minfo
             .MakeGenericMethod(ttype)
             .Invoke(null, new object[] { stream });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.