【问题标题】:GetIterator() and the iterator patternGetIterator() 和迭代器模式
【发布时间】:2013-09-01 03:26:02
【问题描述】:

我正在尝试实现迭代器模式。 基本上,据我了解,它使一个类“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);
        }
    }
}

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

【问题讨论】:

  • 你的代码看起来没问题,不是吗?
  • 它有效...但是为什么呢?我认为设计模式应该有更多的内容......
  • 设计模式只是解决某个设计问题的方法。有时问题可以通过像这样的小改动或单例来解决。
  • 框架中内置了“为什么”。一个设计决定。虽然不是绝对需要实现IEnumerable&lt;&gt;,但它肯定是一个好主意(仅对 Linq 来说)。
  • 好的,但我无法理解幕后发生的事情。我作为枚举器返回的究竟是什么?,当我转到 IEnumerator 定义时,我看到“T Current { get; } " 但是下一步和重置呢?

标签: c# iterator ienumerable ienumerator


【解决方案1】:

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

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() 如何产生实现 CurrentMoveNext 的东西?来自同一部分:

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

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

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

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

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

foreach (int x in myIntCollection)

没有泛型和拳击。整洁。

【讨论】:

  • 哇,每天都有新东西。为什么foreach 可以在仅定义 正确签名的方法而不实现IEnumerable 的类上工作的原因是什么?编辑:我的意思是,超出“规范这么说”的推理。我知道这并不总是可以回答的。 :)
  • 谢谢你!所以如果我明白了,yield 语句会从等式左侧的类型创建一个新的 Enumerable 对象,它实现了所有必要的逻辑?
  • 找到一个'注释,我会添加到我的答案中。
  • @IdanBoadana - 是的,有点。 yield 语句为周围的块调用了很多编译器魔法。
  • 请参阅blogs.msdn.com/b/ericlippert/archive/2011/06/30/… 了解有关此问题的更多想法。
猜你喜欢
  • 2011-07-01
  • 1970-01-01
  • 2011-01-07
  • 2021-01-19
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多