c# - 为什么在 C# 中进行基于模式的编程

标签 c# foreach iterator

想知道为什么 C# 正在转向更多基于模式的编程而不是传统方式。

例。 foreach语句期望循环源有一个名为 GetEnumerator 的魔术方法它返回一个对象,该对象具有更多魔术方法,例如 MoveNextCurrent ,但他们不要求任何特定的接口(interface)? C# 可以强制在 foreach 中使用一个类应该实现 IEnumerableIEnumerable<T>正如它对 using 所做的那样声明它期望在 using 中使用一个对象执行 IDisposable 的语句界面。

此外,我在 async 上看到了类似的趋势。/await还有关键字....

当然这一定有充分的理由,但我觉得理解为什么编译器/CLR 需要“魔术方法”而不是依赖接口(interface)的原因似乎有点奇怪。

最佳答案

foreach

我会说这既是关于性能又是关于兼容性

  • 如果您选择了 foreach使用 IEnumerable它会使所有通用 值类型的集合迭代非常慢 T (因为 装箱/拆箱)。
  • 如果您选择使用 IEnumerable<T>遍历 ArrayList和 来自早期 .NET 版本的所有非泛型集合都不会被 可能。

我认为设计决策很好。当foreach引入 (.NET 1.1) .NET 中没有关于泛型的内容(它们是在 .NET 2.0 中引入的)。选择IEnumerable作为 foreach 的来源枚举会使它与通用集合一起使用时效果不佳,或者需要进行彻底的更改。我想设计师们已经知道他们将在不久之后引入泛型。

此外,将其声明为使用IEnumerable<T>什么时候可用或IEnumerable如果不是 没有太大区别,则使用可用 GetEnumerator方法或不可用时不编译,是吗?

更新

正如@mikez 在评论中提到的,还有一个优势。当你不期待 GetEnumerator返回 IEnumerator/IEnumerator<T>你可以回struct并且在循环使用枚举器时不必担心装箱。

LINQ

当您使用 LINQ 和基于语法的查询时,同样的魔术方法情况也会发生。当你写作时

var results = from item in source
              where item != "test"
              select item.ToLower();

编译器将其转化为

var results = source.Where(x => x != "test")
                    .Select(x => x.ToLower());

而且因为无论什么界面,该代码都可以工作 source实现同样适用于基于语法的查询。只要将其转换为基于方法的查询后,编译器可以正确分配每个方法调用,就可以了。

异步/等待

我不太确定,但我认为同样的事情也适用于 async/await .当您使用这些关键字时,编译器会为您自己生成一堆代码,然后像您自己编写代码一样进行编译。只要通过该转换生成的代码可以编译,一切都可以。

关于c# - 为什么在 C# 中进行基于模式的编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21070640/

相关文章:

c# - 如何删除数组中的第一个元素?

r - R 中网格上大型模拟的并行化

java - `cond`中的 `if (!cond(it.next()))`代表什么?

java - 了解Iterator和Iterable接口(interface)的使用

c++ - 如果 vector 有足够的空间(通过保留创建),std::vector::insert() 是否会使迭代器无效?

c# - 为什么字符串 Remove() 方法允许将字符作为参数?

c# - 应用程序不会以 0 个线程退出

c# - 什么是静态索引器?

javascript - 为什么原生 javascript 数组 forEach 方法明显慢于标准 for 循环?

apache-spark - spark 2.2 struct Streaming foreach writer jdbc sink 滞后