How to Create a Generic Class from a String in C#

How do I create a generic class from a string in C#?

Here is my 2 cents:

Type genericType = typeof(Repository<>);
Type[] typeArgs = { Type.GetType("TypeRepository") };
Type repositoryType = genericType.MakeGenericType(typeArgs);

object repository = Activator.CreateInstance(repositoryType);

Answering the question in comment.

MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething");
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something));
closedMethod.Invoke(repository, new[] { "Query String" });

How to use string as generic type

Take a look at Type.GetType(string):

string name = GetClassName();

Type klass = Type.GetType("Namespace." + name); // Replace "Namespace." with all the namespaces the classes live in, as the argument to `Type.GetType()` should be a fully-qualified name
if (klass is null)
{
// Class was not found
}

Of course, you also need to create an instance of Generic<klass>:

Type genericOfKlass = typeof(Generic<>).MakeGenericType(klass);

Then instantiate it:

object instance = Activator.CreateInstance(genericOfKlass);

Then call .DoSomething() on it:

MethodInfo doSomething = genericOfKlass.GetMethod("DoSomething", BindingFlags.Public | BindingFlags.Instance);
doSomething.Invoke(instance, new object[] { });

As you can see, reflection (this kind of dynamic programming is called reflection) is not easy, but possible in .NET.

Edit: Complete example with request data:

Request request = GetClientRequst();

//container is IContainer of Autofac.

Type requestType = Type.GetType("Namespace." + requestType); // Replace "Namespace." with all the namespaces the classes live in, as the argument to `Type.GetType()` should be a fully-qualified name
Type entityDao = typeof(EntityDao<>).MakeGenericType(requestType);
MethodInfo containerResolve = container.GetType().GetMethod("Resolve");
MethodInfo genericContainerResolve = containerResolve.MakeGenericMethod(entityDao);
object resolveResult = genericContainerResolve.Invoke(container, new object[] { });
MethodInfo create = resolveResult.GetType().GetMethod("Create");
create.Invoke(resolveResult, new object[] { request.Data });

Construct class using string name for generic parameter

Using the answer in ModiX's link applied to your code, should result in something like this:

Type genericType = typeof(Deserializer<>);
Type[] typeArgs = { Type.GetType("Person") };
Type deserializerType = genericType.MakeGenericType(typeArgs);

object deserializer = Activator.CreateInstance(deserializerType);

MethodInfo fromFileMethod = deserializerType.GetMethod("FromFile");
fromFileMethod.Invoke(deserializer, new[] { file });

The line

MethodInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something));

is used if your method is generic, in your case if it would look something like this:

Deserializer<T>.FromFile<T2>(...)

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

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

Instantiate a generic type from string

Like this typeof(GenericRouteHandler<>).MakeGenericType(typeof(MemberHandler));

Of course if you don't have the types you have to use Type.GetType(string) to get the type instead of typeof.

EDIT: Then you have to activate the type Activator.CreateInstance() or invoke a contructor if know the signature myGenericType.GetConstructor(ctorArgsTypes).Invoke(ctorParams); ; it can be faster if cache the consturctors it can be faster then Activator.CreateInstance()

msdn

Generic type from string value

I figured it out, I used InvokeMember to access it. :)

typeHandler.InvokeMember("Handle", BindingFlags.InvokeMethod, null, handler, new[] { requestItem });

Create instance of generic class with dynamic generic type parameter

I found very simple solution to problem. There is no need to cast object to specific type T, just use dynamic keyword instead of casting

   Type myGeneric = typeof(MyComparer<>);
Type constructedClass = myGeneric.MakeGenericType(T);
object created = Activator.CreateInstance(constructedClass);
dynamic comparer = created; // No need to cast created object to T

and then I can use comparer normally to call its methods like:

   return comparer.Equals(myResultAsT, correctResultAsT);

According to LueTm comments, it is probably possible to use reflection again and call comparer methods, but this solution looks much easier.



Related Topics



Leave a reply



Submit