代码之家  ›  专栏  ›  技术社区  ›  thr

在运行时创建未知的泛型类类型对象的实例?

  •  0
  • thr  · 技术社区  · 15 年前

    (我确信这个问题已经被回答过了,我搜索过但找不到)

    我需要在运行时创建几个泛型类型的实例。也就是说,我有一个名为 i 它包含一个介于0-4之间的数字,我需要创建 类型 对象 Action<> , Action<T1> , Action<T1, T2> , Action<T1, T2, T3> Action<T1, T2, T3, T4> 取决于数字是什么(实际情况并不简单,因此它实际上介于0-4之间,我可以使用switch语句)。

    编辑: 澄清我需要 类型 类型的对象,而不是类型的实例。

    5 回复  |  直到 15 年前
        1
  •  3
  •   Nathan Baulch    15 年前

    我能想到的最一般的方法是按名称加载目标操作类型,其中反勾号后面的数字(aka grave accent )表示所需的泛型参数数。

    不幸地 Action<> 在与其他操作类型不同的程序集(mscorlib)中找到,因此在使用此方法时需要以不同的方式处理它。

    public static Type GetActionDelegateType(params Type[] typeArgs)
    {
        var argCount = typeArgs.Length;
        if (argCount == 0) return typeof (Action);
        var defType = argCount == 1
            ? typeof (Action<>) //special case since it's found in mscorlib
            : Type.GetType(string.Format("System.Action`{0}, {1}",
                argCount,
                typeof (Action).Assembly.FullName));
        return defType.MakeGenericType(typeArgs);
    }
    

    您可以使用此测试代码看到上面的代码正在运行:

    for (var i = 0; i <= 4; i++)
    {
        var typeArgs = Enumerable.Repeat(typeof (string), i).ToArray();
        Console.WriteLine(GetActionDelegateType(typeArgs));
    }
    
        2
  •  0
  •   Chriso    15 年前

    我不确定我是否完全理解你想要达到的目标。我试着猜。

    如果您知道所需的类型参数数量永远不会超过四个,那么您可以创建一个数组

    Type[] types = new Type[] { typeof(Action<>), typeof(Action<,>), typeof(Action<,,>) }; // omitted the rest
    

    并提供功能

    int CalculateNumberOfParameters(int i)
    {     
        // I don't know what your i variable really means, but I suggest you have some method to determine a number of type parameters from it).
    }
    

    然后您只需使用类型[CalculateNumberOfParameters(i)]来获取您的操作类型。请注意,我提供了一个非参数化泛型数组,因此您应该对它们调用makeGenericType()以创建实际的可实例化类型。如果您事先知道泛型参数(它们不依赖于i),那么应该在创建类型数组时指定它们。

    如果永远无法知道需要多少泛型参数,则必须在运行时创建类型,因为.NET只定义带有0-4个参数的操作。您仍然需要提供到标准类型之一的转换(或适配器),这样您创建的类型的实例实际上可以从应用程序的其他部分使用。这是一条艰难的路线,我只需要使用它一次(对于Linq表达式序列化),所以除非特别要求,否则我不会深入了解细节。

        3
  •  -1
  •   Andreas Grech    15 年前

    使用 Activator.CreateInstance(string assembly, string classname) .

    “assembly”可以为空(在本例中,在当前程序集中搜索类类型)。“class name”应表示类名,您可以从整数或任何信息中得到类名。

    对于模板类,使用分类字符串形式“classname't1”。

        4
  •  -1
  •   Cecil Has a Name    15 年前

    要么使用 typeof(Action<...>) 在类(静态方式)或 GetType() 实例上的方法(动态方法)。

        5
  •  -1
  •   Manish Basantani    15 年前

    不太确定你在找什么,你从来没有提到从哪里得到T1,T2,T3?

    此代码可能对您有所帮助。

    private static void CreateAppropriateAction(params Type[] argTypes)
            {
                var numberOfArgs = argTypes.Count();
                switch (numberOfArgs)
                {
                    case 1:
                        var oneArgAction = typeof(Action<>).MakeGenericType(argTypes);
                        break;
                    case 2:
                        var twoArgAction = typeof(Action<,>).MakeGenericType(argTypes);
                        break;
                    case 3:
                        var threeArgAction = typeof(Action<,,>).MakeGenericType(argTypes);
                        break;
                    default:
                    //Do nothing or throw exception
                        break;
                }
            }              
    

    然后您可以将此方法与这样的调用一起使用…

    CreateAppropriateAction(typeof(string),typeof(int));