代码之家  ›  专栏  ›  技术社区  ›  Robert C. Barth

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

  •  159
  • Robert C. Barth  · 技术社区  · 17 年前

    标题有点晦涩难懂。我想知道的是这是否可行:

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

    显然,MyGenericClass被描述为:

    public class MyGenericClass<T>
    

    5 回复  |  直到 17 年前
        1
  •  238
  •   momo    10 年前

    你不能不思考就这样做。然而,你

    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);
    
        2
  •  16
  •   JaredPar    17 年前

        3
  •  2
  •   Chris Marisic    11 年前

    还有一些关于如何使用剪刀码运行的附加说明。假设您有一个类似于的类

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

    假设在运行时您有一个

    如果 您可以在需要的编译时进行绑定

    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 方法如果没有完全匹配的类型,它将查找对象参数方法,如果两者都不匹配,将引发运行时绑定异常,警告没有匹配的方法。

    这种方法的明显缺陷是编译时类型安全性的巨大损失。尽管如此,沿着这些思路编写的代码将让您在一个非常动态的意义上进行操作,即在运行时仍然像您期望的那样完全类型化。

        4
  •  2
  •   Nathan Tuggy TonyLuigiC    10 年前

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

    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);
    
        5
  •  0
  •   Todd Skelton    7 年前

    如果您知道将要传递的类型,则可以不经过反射地执行此操作。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;
            }
        }
    }
    
        6
  •  0
  •   EGN    6 年前

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

    推荐文章