2

I'm trying to implement the Iterator pattern. Basically, from what I understand, it makes a class "foreachble" and makes the code more secure by not revealing the exact collection type to the user.

I have been experimenting a bit and I found out that if I implement IEnumerator GetEnumerator() in my class, I get the desired result ... seemingly sparing the headache of messing around with realizing interfaces.

Here is a glimpse to what I mean:

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);
        }
    }
}

I guess my question is, is this a valid example of Iterator? If yes, why is this working, and what can I do to make the iterator return only a part or an anonymous object via "var". If not, what is the correct way ...

4

1 回答 1

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);
        }
    }
}

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

Ecma-334 的规格说:

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

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

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

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

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

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

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

foreach (int x in myIntCollection)

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

于 2013-08-28T22:08:42.163 回答