将实例化的System.Type作为泛型类的类型参数传递

时间:2008-11-05 18:19:52

标签: c# .net generics

标题有点模糊。我想知道的是,如果可能的话:

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

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

显然,MyGenericClass被描述为:

public class MyGenericClass<T>

现在,编译器抱怨'无法找到'myType'的类型或命名空间。“必须有办法实现这一点。

6 个答案:

答案 0 :(得分:202)

没有反思,你不能这样做。但是,你可以用反射来做。这是一个完整的例子:

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 :(得分:14)

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

答案 2 :(得分:2)

另外一些如何使用剪刀代码运行。假设你有一个类似于

的类
public class Encoder() {
public void Markdown(IEnumerable<FooContent> contents) { do magic }
public void Markdown(IEnumerable<BarContent> contents) { do magic2 }
}

假设您在运行时拥有 FooContent

如果你能够在编译时绑定你想要的

var fooContents = new List<FooContent>(fooContent)
new Encoder().Markdown(fooContents)

然而你不能在运行时这样做。要在运行时执行此操作,您可以执行以下操作:

var listType = typeof(List<>).MakeGenericType(myType);
var dynamicList = Activator.CreateInstance(listType);
((IList)dynamicList).Add(fooContent);

动态调用Markdown(IEnumerable<FooContent> contents)

new Encoder().Markdown( (dynamic) dynamicList)

请注意方法调用中dynamic的用法。在运行时dynamicList将是List<FooContent>(另外还是IEnumerable<FooContent>),因为即使使用动态仍然根据强类型语言运行时绑定器将选择适当的Markdown方法。如果没有确切的类型匹配,它将查找对象参数方法,如果两者都不匹配,则将引发运行时绑定异常,提示没有方法匹配。

这种方法的明显缺点是编译时类型安全性的巨大损失。然而,这些代码中的代码将让您以非常动态的方式运行,在运行时仍然可以按照您的预期完全输入。

答案 3 :(得分:2)

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

namespace GenericTest
{
    public class Item
    {
    }
}

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

最后,这就是你如何称呼它。 Define the type with a backtick

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

答案 4 :(得分:0)

如果您知道将传递什么类型,则可以进行反射。 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;
        }
    }
}

答案 5 :(得分:0)

在此代码段中,我想展示如何创建和使用动态创建的列表。例如,我要在此处添加动态列表。

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

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