【问题标题】:Multidimensional arrays do not implement IEnumerable<T>, or do they?多维数组不实现 IEnumerable<T>,是吗?
【发布时间】:2009-04-06 15:06:43
【问题描述】:

由于我仍然不理解 (see this SO question) 的原因,CLR 中的多维数组没有实现 IEnumerable&lt;T&gt;。因此以下内容无法编译:

var m = new int[2,2] {{1, 2}, {3, 4}};
var q = from e in m select e;

那么为什么这个在 VB.NET 中可以正常工作

Sub Main()
    Dim m(,) As Integer = {{1, 2}, {3, 4}}
    Dim q = From e In m Select e

    For Each i In q
        Console.WriteLine(i)
    Next
End Sub

更新:

以下代码有效,因为 C# 编译器将 foreach 替换为 for 循环以遍历每个维度。

foreach(var e in m)
    Console.WriteLine(e);

变成

int[,] numArray3 = new int[,] { { 2, 2 }, { 3, 3 } };
int upperBound = numArray3.GetUpperBound(0);
int num4 = numArray3.GetUpperBound(1);
for (int i = numArray3.GetLowerBound(0); i <= upperBound; i++)
{
    for (int j = numArray3.GetLowerBound(1); j <= num4; j++)
    {
        int num = numArray3[i, j];
        Console.WriteLine(num);
    }
}

【问题讨论】:

  • foreach(...) 之所以有效,是因为 [,] 实现了 IEnumerable(非泛型),而查询需要 IEnumerable
  • 有趣的是,Visual Studio 将 e 的类型显示为 int,而不是您在 IEnumerable 的情况下所期望的对象
  • 另外,我想指出问题是“为什么它在 VB 中有效?”,而不是为什么它不在 C# 中实现
  • 乔尔已回答您的问题。 [,] 没有实现 IEnumerable,但它确实实现了 IEnumerable。您可以自己调用 GetEnumerator() 并伪装成 foreach 循环。
  • 是的,我做到了,它在 VB.Net 中工作,因为它们对 LINQ 查询采取了略有不同的方法,它更倾向于握住程序员的手,并在幕后调用 IEnumerable.Cast() .

标签: c# vb.net arrays clr


【解决方案1】:

查询在 VB.Net 中有效,因为它被转换为

IEnumerable<object> q = m.Cast<object>().Select<object, object>(o => o);

这是可行的,因为您可以在 IEnumerable 上调用 Cast&lt;TResult&gt;(),[*,*] 实现了它。

LINQ 查询在 C# 中不起作用,因为 C# 和 VB.Net 设计者采用了不同的方法。 VB.Net 采用了更多的手把手的方法并修正了你的错误并将IEnumerable 转换为IEnumerable&lt;object&gt; 以便它可以使用。

在 C# 中,您可以使用以下方法进行模拟

var q = from e in m.Cast<object>() select e;

【讨论】:

  • 哇,在花了这么多钱聘请他担任顾问之后。
【解决方案2】:

他们没有在 C# 中本地实现它的原因有两个:

  • 有不止一种方法可以做到。您想要每个“单元格”,还是想要每个“行”?你如何定义'行':[],IEnumerable,其他?如果有两个以上的维度怎么办?一旦他们选择了一种方式,一大群开发人员就会告诉他们他们应该采用不同的方式。
  • 多亏了迭代器块和yield 关键字,您可以很容易地根据您当时的需要实现自己的。当然,这是一个 C# 构造,但在 VB 中并没有那么那么难。

【讨论】:

  • 但是从问题中可以看出,VB.NET不需要它。
  • @prankster:这可能是因为 VB 的根源。 VB.Net 继承了很多手持编程方面的内容。您希望如何实现 IEnumerable 的假设就是其中之一。
  • ... 在恶作剧者的评论后的第一句末尾添加了“in C#”。
【解决方案3】:

MSDN page for Array 包括:

重要提示: 在 .NET Framework 2.0 版中,Array 类实现 System.Collections.Generic.IList、System.Collections.Generic.ICollection 和 System.Collections.Generic.IEnumerable 泛型接口。这些实现在运行时提供给数组,

请注意引用中的最后一句话...看来这一代不会发生在多维数组中(因此是一个文档错误)。

但正如其他人所指出的,T 会是什么?可以为 T[] 提供一个很好的案例(或者,现在使用 LINQ,IEnumerable&lt;T&gt;)。

最后,如果您想迭代数组的所有成员,只需坚持使用 IEnumerable 和 Cast 扩展名。否则很容易自己编写。

【讨论】:

    【解决方案4】:

    提示:使用类型化范围变量代替 Cast()


    塞缪尔说:

    在 C# 中,你可以通过使用来模拟这个

    var q = from e in m.Cast<object>() select e;
    // q is of type IEnumerable<object>
    

    就在 C# 中模仿 VB 而言,这当然是正确的,但是您会丢失类型信息。相反,简单地声明范围变量要容易得多,而且可读性更好。

    以下编译,性能更好,类型安全且不会丢失类型信息:

    var m = new int[2, 2] { { 1, 2 }, { 3, 4 } };
    var q = from int e in m select e;
    // q is of type IEnumerable<int>
    

    在最初的建议中,您将拥有一个IEnumerable&lt;object&gt;,使用int e 将其更改为IEnumerable&lt;int&gt;,这有其优势。

    【讨论】:

      猜你喜欢
      • 2010-09-21
      • 1970-01-01
      • 2011-02-15
      • 2014-12-04
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      相关资源
      最近更新 更多