简体   繁体   中英

Create instance of class with generic type and call method of same generic type from string name of object at runtime

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

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" to Type.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);

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM