繁体   English   中英

以下为什么不工作? (IEnumerable / IEnumerator)

[英]Why doesn't the following work? (IEnumerable/ IEnumerator)

我在这个MSDN页面上尝试了这个例子。 我试图更改GetEnumerator方法。 我知道有些东西似乎不对,但它符合,然后不运行。 错误是Enumerator尚未启动并且应该MoveNext ,但它正在被调用!

class Program
{
    static void Main(string[] args)
    { 
        foreach (var day in new DaysOfTheWekk())
        {
            Console.WriteLine(day) ;
        }
        Console.ReadLine();
    }
}

public class DaysOfTheWekk: IEnumerable
{
    private string[] days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    public IEnumerator GetEnumerator()
    {
        days.GetEnumerator().MoveNext();
        yield return days.GetEnumerator().Current;
    }
}

你为什么要打电话给moveNext? 请忽略.Current

public class DaysOfTheWeek: IEnumerable
{
    private string[] days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    public IEnumerator GetEnumerator()
    {
        return days.GetEnumerator();
    }
}

否则使用while循环,因为:

public class DaysOfTheWeek: IEnumerable
{
    private string[] days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    public IEnumerator GetEnumerator()
    {
        var enumerator = days.GetEnumerator();
        while(enumerator.MoveNext())
        { 
            yield return enumerator.Current;
        }
    }
}

说明: GetEnumerator()方法总是返回一个新的枚举器,因此如果调用GetEnumerator().Current ,则不会在新返回的实例上MoveNext()函数! 请使用我的第二个示例中所述的变量。

您已在另一个枚举器上调用了MoveNext()

你的代码相当于

public IEnumerator GetEnumerator()
{
    var enumerator1 = days.GetEnumerator();
    enumerator1.MoveNext();
    var enumerator2 = days.GetEnumerator();
    yield return enumerator2.Current;
}

每次调用GetEnumerator() ,都会构造一个新的枚举器(至少对于IEnumerable BCL实现),正如您从上面的代码中看到的那样,您构造了两个枚举器并在一个上调用MoveNext而在另一个上调用Current。 这是属性和方法之间的关键概念差异。 应该期望一个方法返回一个操作的结果,而一个属性应该返回相同的值,除非该对象的状态发生了变化。 您的代码中似乎也存在逻辑错误,您只返回第一个元素,如果没有则会失败,所以基本上您已经实现了.Single()方法,如果您更改为

public IEnumerator GetEnumerator()
{
    var enumerator = days.GetEnumerator();
    while(enumerator.MoveNext()){
       yield return enumerator.Current;
    }
}

这当然与功能相同

public IEnumerator GetEnumerator()
{
    foreach(var day in days){
       yield return day;
    }
}
days.GetEnumerator().MoveNext();
yield return days.GetEnumerator().Current;

在这里,您可以创建两个不同的枚举器。 您在第一个上调用MoveNext ,然后在下面的行中创建另一个并在其上访问Current

另一种解决方案是,在调用方法GetEnumerator()时,应确保始终返回相同的迭代器。 这是示例实现:

public class DaysOfTheWeek : IEnumerable
{
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    private IEnumerator iterator;

    public DaysOfTheWeek()
    {
        iterator = days.GetEnumerator();
        iterator.MoveNext();
    }

    public IEnumerator GetEnumerator()
    {
        return iterator;
    }
}

不需要在构造函数中调用MoveNext(),您必须在iterator.current之前调用iterator.MoveNext()方法。

关键是当您调用GetEnumerator()方法时,您将始终使用相同的迭代器。

我想你假设days.GetEnumerator()总是返回相同的枚举器。 它有一个很好的理由每次返回一个新的 - 如果只有一个,不同的代码片段无法同时枚举。 它组成不好。

调用days.GetEnumerator()一次,或写入return days.GetEnumerator();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM