【问题标题】:List<T> Constructor (IEnumerable<T>) doesn't accept an array created from Array.CreateInstance(Type, Int32)List<T> 构造函数 (IEnumerable<T>) 不接受从 Array.CreateInstance(Type, Int32) 创建的数组
【发布时间】:2014-12-02 06:36:54
【问题描述】:

我是编程和 .net 的新手,我很难理解为什么使用 List&lt;T&gt;(IEnumerable&lt;T&gt;) 构造函数接受使用 [] 创建的数组,但不接受使用 Array.CreateInstance(Type, Int32) 创建的数组。

以下是有效的:

DirectoryInfo[] dirsArray = foo.GetDirectories();
List<DirectoryInfo> dirsList = new List<DirectoryInfo>(dirsArray);

以下是没有的:

 Array dirsArray = Array.CreateInstance(typeof(DirectoryInfo), 10); //assume we know 10 is the required length
 List<DirectoryInfo> dirsList = new List<DirectoryInfo>(dirsArray);

上面给出了以下编译错误:

Error   1   The best overloaded method match for 'System.Collections.Generic.List<System.IO.DirectoryInfo>.List(System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo>)' has some invalid arguments

Error   2   Argument 1: cannot convert from 'System.Array' to 'System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo>'

但我知道List&lt;T&gt;(IEnumerable&lt;T&gt;) 可以接受任何IEnumerable 作为参数。我知道System.ArrayIEnumerable。不仅因为这在参考文献中,还因为第一个使用 [] 构造函数语法的示例运行良好。

那么这里的问题是什么? Array.CreateInstance 是否设法创建了一个不是 IEnumerable 的数组?

【问题讨论】:

  • 因为Array.CreateInstance 返回一个未类型化的Array,它没有实现IEnumerable&lt;T&gt;
  • 您想通过使用Array.CreateInstance 解决什么问题?我个人从来没有发现它的用途。
  • 其实我想把ControlCollection转成List,不知道怎么做。所以我添加了一个步骤,先将其转换为数组,然后再将其转换为列表。

标签: c# .net arrays


【解决方案1】:

Array.CreateInstance 返回一个无类型的Array,您会注意到它没有实现IEnumerable&lt;T&gt;(它不是通用的),因此不能与List&lt;T&gt; 构造函数一起使用。

但是,Array.CreateInstance 实际返回的内容是类型化的,您只需将其强制转换为您想要的类型(所有类型化数组都派生自 Array 基类)。所以你可以这样做:

List<DirectoryInfo> dirsList = new List<DirectoryInfo>((DirectoryInfo[])dirsArray);

它应该可以编译。

也就是说,我从来没有找到使用 Array.CreateInstance 的理由。

更新:由于在原始问题的 cmets 中您谈到将 ControlCollection 转换为 List&lt;Control&gt;,因此应注意您不能将 ControlCollection 转换为类型化数组。所以这样的事情是行不通的:

var lst = (Control[])myControlCollection;

因为ControlCollection(以及框架中的许多旧的、前泛型的集合)不是从Array 派生的。在这种情况下,由于ControlCollection 实现了IEnumerable,您可以使用Cast 扩展方法:

var lst = new List<Control>(myControlCollection.Cast<Control>());

如果框架中的许多集合类都实现了IEnumerable,您就可以使用这个技巧。 MatchCollection 再举一个例子。

【讨论】:

    【解决方案2】:

    Array 类本身不是IEnumerable&lt;T&gt;。您需要转换Array.CreateInstance 的结果

    var dirsArray = (DirectoryInfo[]) Array.CreateInstance(typeof(DirectoryInfo), 10);
    

    Array 是所有数组类型的基类,IEnumerable&lt;T&gt; 的实现是在运行时提供的。因此在编译时不能将数组用作IEnumerable&lt;T&gt;。来自MSDN

    从 .NET Framework 2.0 开始,Array 类实现了System.Collections.Generic.IList&lt;T&gt;System.Collections.Generic.ICollection&lt;T&gt;System.Collections.Generic.IEnumerable&lt;T&gt; 通用接口。 在运行时将实现提供给数组,因此,泛型接口不会出现在 Array 类的声明语法中。

    【讨论】:

      【解决方案3】:

      因为Array.CreateInstance(Type, Int32) 不返回IEnumerable&lt;T&gt; 实例,所以它返回Array 对象。如果您使用 [] 创建一个数组,它将是一个IEnumerable&lt;T&gt;

      请看一下这个帖子,它很有解释性:Why isn't Array a generic type?

      【讨论】:

      • 这是我不明白的部分。在 CreateInstance 的参考中,它只是声明它返回一个 System.Array。没有提到它没有任何不同。在 System.Array 的参考资料中,它明确指出它是 IEnumerable。
      • 它是一个 IEnumerable,只是不是一个 IEnumerable
      • @GarryWong IEnumerableIEnumerable&lt;T&gt; 是两个不同的东西。
      • 哦!好的,这就是我所缺少的。谢谢:)
      猜你喜欢
      • 2016-03-19
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 2011-03-17
      • 2015-05-28
      • 1970-01-01
      相关资源
      最近更新 更多