将 List<> 转换为数组 - 我得到“尝试将元素作为与数组不兼容的类型来访问。”

Posted

技术标签:

【中文标题】将 List<> 转换为数组 - 我得到“尝试将元素作为与数组不兼容的类型来访问。”【英文标题】:Converting a List<> to an Array - I get "Attempted to access an element as a type incompatible with the array." 【发布时间】:2011-03-25 16:24:04 【问题描述】:

我正在尝试遍历一堆项目,每个项目都有一个 List 对象数组,我想将这些对象转换为数组数组。这是执行此操作的代码:

foreach (IngredientNode i in _snapshot._ingredientMap.Values)

   for (int c = 0; c < NUM_TAGS; c++)
   
      if (i.RecipesByTag[c] == null) continue;
      i.RecipesByTag[c] = i.RecipesByTag[c].ToArray<RecipeNode>();
    <--- EXCEPTION

RecipesByTag 的静态类型为 IEnumerable&lt;RecipeNode&gt;[]。但是,它的动态类型是List&lt;RecipeNode&gt;[]。我想逐一检查并转换 RecopeNode[] 的动态类型。在调试器下,这可以工作并且 i.RecipesByTag 被转换。但是,最后一个大括号会抛出异常:

试图以与数组不兼容的类型访问元素。

我感觉正在发生某种堆栈损坏。有人可以在这里解释技术层面发生的事情吗?谢谢!

迈克

【问题讨论】:

【参考方案1】:

您不应该为ToArray 方法指定类型参数,如果您使用强类型集合,则应该从它的用法中推断出来。这是一个通用类型转换问题。您正试图将元素放入某种不兼容类型的数组中。

你的问题应该归结为这个(这些数组是协变的):

object[] obj = new string[1];
obj[0] = 5; // compiles fine, yields runtime error

现在,同样的事情,不同的类型(这些数组也是协变的):

IEnumerable<int>[] x = new List<int>[1];
x[0] = new int[1]; // compiles fine, yields runtime error

类型系统不喜欢这样的原因应该很明显了。基本上,您将其视为IEnumerable&lt;int&gt; 的数组,但它实际上是List&lt;int&gt; 的数组。您不能将不相关的 int 类型数组放入该数组中。

我相信 Eric Lippert 在他的 blog 上很好地解释了这一点。

【讨论】:

.NET Runtime 2.0,C# 3.5 编译器..顺便说一句,上面会导致同样的错误。 据我所知,这是一个运行时错误,错误限制。如果您有一个可枚举数组,则不能将该数组中的一个元素设置为另一个数组。编译器允许它,因为数组是可枚举类型,所以静态类型匹配。然而,当一个数组自发地变成多维数组时,宇宙就会内爆,整个内存结构就会被破坏。运行时不够聪明,无法将所有内容移到内存中。我想出了一个解决方法,我会发布答案。 这不是运行时错误。这是适用于数组的协变类型规则。您实际上可以使用数组,这样您就不会遇到编译器错误而是运行时错误。 我从来没有说过这是一个错误,我说的是限制:) 一旦我想到数组在内存中的实际布局方式,它就很有意义。但是,它确实显示了一些关于编译器如何工作的信息。当我说 foo[5] = someArray 时,它期望 foo 是一个多维数组。仅仅让 foo[5] 成为指向堆上某个位置的另一个数组的指针是不够聪明的。 很好,“据我所知,这是一个运行时错误,错误限制。”我读到这是一个错误,但甚至没有注意到错误限制部分。问题不在于内存分配,而在于运行时如何解释类​​型信息。我已经更新了我的答案以反映这一点。如果您愿意,您应该能够创建一个独立的测试用例。【参考方案2】:

好的,我想我知道发生了什么......我有一个 Enumerables 数组。起初,这是一个指向列表对象的指针数组。我改为将其设为其他数组的数组,换句话说,我将我的数组转换为多维数组。由于多维数组在内存中是连续的(与指向其他数组的指针数组相反),这样做会完全破坏内存中的数组。至少这是我的理论。

我所做的是从头开始完全重新创建 i.RecipesByTag。像这样的:

List<RecipeNode[]> temp = new List<RecipeNode[]>();

for (int c = 0; c < NUM_TAGS; c++)

   RecipeNode[] nodes = (i.RecipesByTag[c] == null) ? null : i.RecipesByTag[c].ToArray<RecipeNode>();
   temp.Add(nodes);


i.RecipesByTag = temp.ToArray();

这很好用。

【讨论】:

以上是关于将 List<> 转换为数组 - 我得到“尝试将元素作为与数组不兼容的类型来访问。”的主要内容,如果未能解决你的问题,请参考以下文章

如何将 C# List<string[]> 转换为 Javascript 数组?

是否可以将 MVC C# List<int> 转换为 javascript 数组?

将 List<List<Integer>> 转换为 int[][]

将java list转换为js的数组

将 ArrayList 转换为特定类型的数组 [重复]

string.split 返回一个字符串 [] 我想要一个 List<string> 是不是有一个内衬可以将数组转换为列表?