标题有点模糊。我想知道这是否可能:

string typeName = <read type name from somwhere>;
Type myType = Type.GetType(typeName);

MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>();

显然,MyGenericClass被描述为:

public class MyGenericClass<T>

现在,编译器报错“找不到类型或名称空间‘myType’”。一定有办法解决的。


当前回答

你不能不反思就这么做。但是,可以通过反射来实现。下面是一个完整的例子:

using System;
using System.Reflection;

public class Generic<T>
{
    public Generic()
    {
        Console.WriteLine("T={0}", typeof(T));
    }
}

class Test
{
    static void Main()
    {
        string typeName = "System.String";
        Type typeArgument = Type.GetType(typeName);

        Type genericClass = typeof(Generic<>);
        // MakeGenericType is badly named
        Type constructedClass = genericClass.MakeGenericType(typeArgument);

        object created = Activator.CreateInstance(constructedClass);
    }
}

注意:如果你的泛型类接受多个类型,当你省略类型名时,你必须包括逗号,例如:

Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);

其他回答

不幸的是,没有。泛型参数必须在编译时可解析为1)有效类型或2)另一个泛型参数。如果不使用反射,就无法根据运行时值创建通用实例。

我的要求略有不同,但希望能帮助到别人。我需要从配置中读取类型并动态实例化泛型类型。

namespace GenericTest
{
    public class Item
    {
    }
}

namespace GenericTest
{
    public class GenericClass<T>
    {
    }
}

最后,你可以这样称呼它。用反勾号定义类型。

var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest");
var a = Activator.CreateInstance(t);

你不能不反思就这么做。但是,可以通过反射来实现。下面是一个完整的例子:

using System;
using System.Reflection;

public class Generic<T>
{
    public Generic()
    {
        Console.WriteLine("T={0}", typeof(T));
    }
}

class Test
{
    static void Main()
    {
        string typeName = "System.String";
        Type typeArgument = Type.GetType(typeName);

        Type genericClass = typeof(Generic<>);
        // MakeGenericType is badly named
        Type constructedClass = genericClass.MakeGenericType(typeArgument);

        object created = Activator.CreateInstance(constructedClass);
    }
}

注意:如果你的泛型类接受多个类型,当你省略类型名时,你必须包括逗号,例如:

Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);

如果您知道将传递什么类型,则可以在不反射的情况下执行此操作。switch语句可以工作。显然,这只在有限的情况下有效,但它会比反射快得多。

public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}

在这段代码中,我将展示如何创建和使用动态创建的列表。例如,我正在添加到这里的动态列表中。

void AddValue<T>(object targetList, T valueToAdd)
{
    var addMethod = targetList.GetType().GetMethod("Add");
    addMethod.Invoke(targetList, new[] { valueToAdd } as object[]);
}

var listType = typeof(List<>).MakeGenericType(new[] { dynamicType }); // dynamicType is the type you want
var list = Activator.CreateInstance(listType);

AddValue(list, 5);

类似地,您可以调用列表上的任何其他方法。