GetIterator() 和迭代器模式

Ida*_*ana 2 c# ienumerable ienumerator iterator

我正在尝试实现迭代器模式。基本上,据我所知,它使类成为“foreachble”,并通过不向用户透露确切的集合类型来使代码更安全。

我一直在试验,我发现如果我在我的类中实现 IEnumerator GetEnumerator(),我得到了想要的结果......似乎可以省去搞乱实现接口的麻烦。

这是我的意思的一瞥:

public class ListUserLoggedIn
{
    /*
        stuff
    */
    
    public List<UserLoggedIn> UserList { get; set; }

    public IEnumerator<UserLoggedIn> GetEnumerator()
    {
        foreach (UserLoggedIn user in this.UserList)
        {
            yield return user;
        }
    }

    public void traverse()
    {
        foreach (var item in ListUserLoggedIn.Instance)
        {
            Console.Write(item.Id);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想我的问题是,这是迭代器的有效示例吗?如果是,为什么这是有效的,我该怎么做才能使迭代器通过“var”仅返回一部分或匿名对象。如果不是,正确的方法是什么...

Hen*_*man 5

首先是一个更小和简化的独立版本:

class Program
{
    public IEnumerator<int> GetEnumerator()  // IEnumerable<int> works too.
    {
        for (int i = 0; i < 5; i++)     
            yield return i;     
    }

    static void Main(string[] args)
    {
        var p = new Program();

        foreach (int x in p)
        {
            Console.WriteLine(x);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的“奇怪”之处在于class Program没有实现IEnumerable.

Ecma-334 的规范说:

§ 8.18 迭代器
foreach 语句用于迭代可枚举集合的元素。为了可枚举,集合应具有返回枚举器的无参数 GetEnumerator 方法。

所以这就是为什么foreach()在你的课堂上工作的原因。没有提到 IEnumerable。但是 GetEnumerator() 如何产生实现Currentand 的东西MoveNext?来自同一部分:

迭代器是产生有序值序列的语句块。迭代器与普通语句块的区别在于是否存在一个或多个 yield 语句

重要的是要理解迭代器不是一种成员,而是实现函数成员的一种方式

所以你的方法的主体是一个迭代器块,编译器检查一些约束(该方法必须返回一个 IEnumerable 或 IEnumerator),然后IEnumerator为你实现成员。

对于更深层次的“为什么”,我也学到了一些东西。基于 Eric Lippert 在“The C# Programming Language 3rd”,第 369 页中的注释:

这被称为“基于模式的方法”,它可以追溯到泛型之前。C#1 中基于接口的方法将完全基于传递object,并且值类型总是必须被装箱。模式方法允许

foreach (int x in myIntCollection)

没有泛型和拳击。整洁的。