【问题标题】:How can I create an instance of an arbitrary Array type at runtime?如何在运行时创建任意 Array 类型的实例?
【发布时间】:2016-07-04 03:47:42
【问题描述】:

我试图在编译时反序列化一个未知类型的数组。在运行时我发现了类型,但我不知道如何创建实例。

类似:

Object o = Activator.CreateInstance(type);

这不起作用,因为没有无参数的构造函数,Array 似乎没有任何构造函数。

【问题讨论】:

    标签: c# reflection compact-framework .net-2.0


    【解决方案1】:

    【讨论】:

    • 这有点问题。如果我知道类型是 System.String[] 而我 Array.CreateInstance() 我得到一个 System.String[][]
    • 是的,你传入的是 element 类型,而不是最终的数组类型。
    【解决方案2】:

    您可以使用 Array 的 CreateInstance 重载之一,例如:-

    object o = Array.CreateInstance(type, 10);
    

    【讨论】:

      【解决方案3】:

      相当老的帖子,但在回答一个新问题时,虽然发布了一个创建多维数组的相关示例。

      假设类型(elementType)为int,以二维数组为例。

      var size = new[] { 2, 3 };                
      var arr = Array.CreateInstance(typeof(int), size);
      

      例如,当它是二维时,它可以填充为

      var value = 1;
      for (int i = 0; i < size[0]; i++)
          for (int j = 0; j < size[1]; j++)
              arr.SetValue(value++, new[] { i, j });
      //arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
      

      【讨论】:

        【解决方案4】:

        另一种方法是使用表达式树来提高性能。例如如果你有数组 type, type 你可以这样做

        var ctor = type.GetConstructors().First(); // or find suitable constructor
        var argsExpr = ctor.GetParameters().Select(x => Expression.Constant(0)); 
        var func = Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();
        

        这只是返回一个空数组。可能不是很有用。 MSDN 声明 GetConstructors 不保证任何顺序,因此您可能需要一个逻辑来找到具有正确参数的正确构造函数,以便以正确的大小进行实例化。例如你可以这样做:

        static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
        {
            var ctor = type
                .GetConstructors()
                .OrderBy(x => x.GetParameters().Length) // find constructor with least parameters
                .First();
        
            var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
            return Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();
        }
        

        使用Expression.NewArrayBounds 而不是Expression.New 可以更轻松地实现相同的目标,如果你得到的只是数组元素类型,而不是数组类型本身,它就更有效了。演示:

        static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
        {
            var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
            var newExpr = Expression.NewArrayBounds(type.GetElementType(), argsExpr);
            return Expression.Lambda<Func<object>>(newExpr).Compile();
        }
        
        // this exercise is pointless if you dont save the compiled delegate, but for demo purpose:
        
        x = string[] {...
        y = ArrayCreateInstance(x.GetType(), 10)(); // you get 1-d array with size 10
        
        x = string[,,] {...
        y = ArrayCreateInstance(x.GetType(), 10, 2, 3)(); // you get 3-d array like string[10, 2, 3]
        
        x = string[][] {...
        y = ArrayCreateInstance(x.GetType(), 10)(); // you get jagged array like string[10][]
        

        如果您传递的是元素类型本身,只需将 type.GetElementType() 更改为 type

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-21
          • 1970-01-01
          • 2011-11-25
          • 1970-01-01
          相关资源
          最近更新 更多