为什么在C#中基于模式的编程

时间:2014-01-12 02:36:56

标签: c# foreach iterator

想知道为什么C#正朝着更多基于模式的编程而不是传统方式发展。

实施例。 foreach语句要求循环源有一个名为GetEnumerator的魔术方法,该方法返回一个对象,该对象具有更多魔法方法,如MoveNextCurrent,但它们不会不要求任何特定的界面? C#可能要求foreach中使用的类应该像IEnumerable语句一样实现IEnumerable<T>using,因为它期望在using语句中使用对象实现IDisposable接口的async语句。

另外,我也看到了与await / {{1}}个关键字类似的趋势....

当然必须有一个很好的理由,但对于我来说理解编译器/ CLR需要“魔术方法”而不是依赖接口的原因似乎有点奇怪。

1 个答案:

答案 0 :(得分:12)

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实现,该代码都可以工作,这同样适用于基于语法的查询。只要将其转换为基于方法的查询,每个方法调用都可以由编译器正确分配,一切正常。

异步/ AWAIT

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