如何在C#中实现foreach?
在C#中如何实现foreach
?
我想它的一部分看起来像:
var enumerator = TInput.GetEnumerator(); while(enumerator.MoveNext()) { // do some stuff here }
但是我不确定究竟发生了什么。 返回enumerator.Current
器使用什么方法。每个循环的当前流程? 它是为[每个周期]返回还是采用匿名函数或其他东西来执行foreach
的主体?
它不使用匿名函数,不。 基本上,编译器将代码转换为与此处显示的while循环大致相同的代码。
foreach
不是一个函数调用 – 它内置于语言本身,就像循环和while
循环一样。 它不需要返回任何东西或“接受”任何类型的function。
请注意, foreach
有一些有趣的皱纹:
有关详细信息,请参阅C#4规范的第8.8.4节。
惊讶的是没有触及确切的实现。 虽然您在问题中发布的内容是最简单的forms,但完整的实现(包括枚举器处理,转换等)在规范的8.8.4部分中。
现在有两种情况可以在类型上运行foreach
循环:
-
如果类型具有名为
GetEnumerator
的公共/非静态/非generics/无参数方法,该方法返回具有公共MoveNext
方法和公共Current
属性的内容。 正如Eric Lippert先生在这篇博客文章中指出的那样 ,这是为了在价值类型的情况下适应类型安全和拳击相关性能问题的预先通用时代。 请注意,这是鸭子打字的情况。 例如,这有效:class Test { public SomethingEnumerator GetEnumerator() { } } class SomethingEnumerator { public Something Current //could return anything { get { return ... } } public bool MoveNext() { } } //now you can call foreach (Something thing in new Test()) //type safe { }
然后由编译器将其翻译为:
E enumerator = (collection).GetEnumerator(); try { ElementType element; //pre C# 5 while (enumerator.MoveNext()) { ElementType element; //post C# 5 element = (ElementType)enumerator.Current; statement; } } finally { IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); }
-
如果类型实现
IEnumerable
,其中GetEnumerator
返回具有公共MoveNext
方法和公共Current
属性的IEnumerator
。 但是一个有趣的子案例是即使你明确地实现IEnumerable
(即Test
类上没有公共的GetEnumerator
方法),你也可以有一个foreach
。class Test : IEnumerable { IEnumerator IEnumerable.GetEnumerator() { } }
这是因为在这种情况下,
foreach
实现为(假设类中没有其他公共GetEnumerator
方法):IEnumerator enumerator = ((IEnumerable)(collection)).GetEnumerator(); try { ElementType element; //pre C# 5 while (enumerator.MoveNext()) { ElementType element; //post C# 5 element = (ElementType)enumerator.Current; statement; } } finally { IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); }
如果类型显式实现
IEnumerable
那么foreach
将转换为(假设类中没有其他公共GetEnumerator
方法):IEnumerator
enumerator = ((IEnumerable )(collection)).GetEnumerator(); try { ElementType element; //pre C# 5 while (enumerator.MoveNext()) { ElementType element; //post C# 5 element = (ElementType)enumerator.Current; //Current is `T` which is cast statement; } } finally { enumerator.Dispose(); //Enumerator implements IDisposable }
几个有趣的事情需要注意:
-
在上述两种情况下,
Enumerator
类都应具有公共MoveNext
方法和公共Current
属性。 换句话说, 如果您正在实现IEnumerator
接口,则必须隐式实现它。 例如,foreach
适用于此枚举器:public class MyEnumerator : IEnumerator { void IEnumerator.Reset() { throw new NotImplementedException(); } object IEnumerator.Current { get { throw new NotImplementedException(); } } bool IEnumerator.MoveNext() { throw new NotImplementedException(); } }
(感谢Roy Namir指出这一点
foreach
实施并不像表面上看起来那么简单) -
枚举器优先级 – 就像你有一个
public GetEnumerator
方法一样,那么这是foreach
的默认选择,无论是谁实现它。 例如:class Test : IEnumerable
{ public SomethingEnumerator GetEnumerator() { //this one is called } IEnumerator IEnumerable .GetEnumerator() { } } 如果您没有公共实现(即只有显式实现),那么优先级就像
IEnumerator
>>IEnumerator
。 -
有一个转换操作符参与
foreach
的实现,其中collection元素被转换回类型(在foreach
循环本身中指定)。 这意味着即使您已经像这样写了SomethingEnumerator
:class SomethingEnumerator { public object Current //returns object this time { get { return ... } } public bool MoveNext() { } }
你可以写:
foreach (Something thing in new Test()) { }
因为
Something
与object
类型兼容,所以使用C#规则,或者换句话说,如果两种类型之间存在显式转换,编译器会允许它。 否则编译器会阻止它。 实际演员表在运行时执行,可能会或可能不会失败。上述就是C#学习教程:如何在C#中实现foreach?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/988674.html