迭代器

.Net技术 码拜 8年前 (2016-03-06) 1005次浏览
先看教材迭代器
本人有两个问题:
第一个问题:它书上前面有一句话 它说 这个方法可以通过IEnumerable接口的实现代码来获得,但这是可选的。问一下什么叫但这是可选的?假如能举个简单的代码例子再好不过了。
第二个问题:本人划下来的2号句子,里面有2个主题,能不能分别给本人举一个简单的代码例子来说明它们。请不要用泛型谢谢了
解决方案

26

引用 7 楼 weikeli19 的回复:
Quote: 引用 6 楼 shingoscar 的回复:

要迭代一个对象只要实现IEnumerator即可,IEnumerable只是为了方便写foreach,所以不是必须的

五星红旗人  那你举一个简单的代码例子来说明IEnumerable不是必须的

你别用foreach就行了啊

var list = new ArrayList();
var itor = list.GetEnumerator();
while(itor.MoveNext())
{
    var item = itor.Current;
}

28

实际上,例如说对于数组,编译器遇见 foreach 语句时就直接使用地址偏移来取数了。编译器做的事情比想象的多。
这本书的作者,在这里实际上还是谈 IEnumerable 接口为主。只是随口提了一下“可选的”而又没有解释。

34

引用 9 楼 sp1234 的回复:

对于第一个问题:
一开始,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(); }
    }
}

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明迭代器
喜欢 (0)
[1034331897@qq.com]
分享 (0)