我试图实现迭代器模式。 基本上从我的理解,它使一个类“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”只返回一个部分或一个匿名对象。 如果没有,那么正确的方法是什么..
答案 0 :(得分:4)
首先是一个较小且简化的自包含版本:
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在“C#Programming Language 3rd”中的注释,第369页:
这被称为“基于模式的方法”,它可以追溯到仿制药之前。 C#1中基于接口的方法完全基于传递
object
,并且值类型总是必须加框。模式方法允许
foreach (int x in myIntCollection)
没有泛型而没有拳击。整齐。