先看教材
本人有两个问题:
第一个问题:它书上前面有一句话 它说 这个方法可以通过IEnumerable接口的实现代码来获得,但这是可选的。问一下什么叫但这是可选的?假如能举个简单的代码例子再好不过了。
第二个问题:本人划下来的2号句子,里面有2个主题,能不能分别给本人举一个简单的代码例子来说明它们。请不要用泛型谢谢了
本人有两个问题:
第一个问题:它书上前面有一句话 它说 这个方法可以通过IEnumerable接口的实现代码来获得,但这是可选的。问一下什么叫但这是可选的?假如能举个简单的代码例子再好不过了。
第二个问题:本人划下来的2号句子,里面有2个主题,能不能分别给本人举一个简单的代码例子来说明它们。请不要用泛型谢谢了
解决方案
26
你别用foreach就行了啊
var list = new ArrayList(); var itor = list.GetEnumerator(); while(itor.MoveNext()) { var item = itor.Current; }
28
实际上,例如说对于数组,编译器遇见 foreach 语句时就直接使用地址偏移来取数了。编译器做的事情比想象的多。
这本书的作者,在这里实际上还是谈 IEnumerable 接口为主。只是随口提了一下“可选的”而又没有解释。
这本书的作者,在这里实际上还是谈 IEnumerable 接口为主。只是随口提了一下“可选的”而又没有解释。
34
对于第一个问题:
一开始,c# 编译器可能想去找接口、…
这里可能有C#的历史原因。
Dotnet 1.0开始就支持接口,因此,接口缺失的可能性比较小。
但是,1.0还没有泛型,不能有相似IEnumerable<int>的写法。
假如迭代一定要用及接口实现,那么IEnumerator.Current就必须返回object。也就是说,对于int等值类型,有装箱/拆箱的性能损失。由于迭代可以是编译器把戏,完全可以在编译期展开而不需要运行时强类型支持。微软可能(目前没有一手证据)出于性能优化,允许签名的方式来实现迭代。
以下代码在显示本人的机器上性能差异(2毫秒 对 22毫秒):
using System; using System.Collections; using System.Diagnostics; class Program { static void Main(string[] args) { Stopwatch sw = Stopwatch.StartNew(); foreach (int i in new MyCollection()) { } Console.WriteLine("MyCollection: {0}ms", sw.ElapsedMilliseconds); // 结果: 2ms sw = Stopwatch.StartNew(); foreach (int i in new MyCollectionWithInterface()) { } Console.WriteLine("MyCollectionWithInterface: {0}ms", sw.ElapsedMilliseconds); // 结果: 22ms Console.ReadLine(); } } class MyCollection { public MyEnumerator GetEnumerator() { return new MyEnumerator(); } public class MyEnumerator { int i = -1; public int Current { get { return i; } } // 区别:返回int,不需要装箱(和随后的拆箱) public bool MoveNext() { return ++i < 1000 * 1000; } public void Reset() { throw new NotImplementedException(); } } } class MyCollectionWithInterface : IEnumerable { public IEnumerator GetEnumerator() { return new MyEnumerator(); } class MyEnumerator : IEnumerator { int i = -1; public object Current { get { return i; } } // 区别: 返回object,需要装箱 public bool MoveNext() { return ++i < 1000 * 1000; } public void Reset() { throw new NotImplementedException(); } } }