简体   繁体   English

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

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

I was trying out the example on this MSDN page . 我在这个MSDN页面上尝试了这个例子。 I tried to change the GetEnumerator method. 我试图更改GetEnumerator方法。 I know something doesn't seem right in that, but it complies and then doesn't run. 我知道有些东西似乎不对,但它符合,然后不运行。 Error is that the Enumerator has not started and that MoveNext should be called, but it is being called! 错误是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;
    }
}

Why do you want to call moveNext? 你为什么要打电话给moveNext? Just leave out the .Current : 请忽略.Current

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

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

Otherwise use a while loop since: 否则使用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;
        }
    }
}

Explanation: The GetEnumerator() method always returns a new enumerator, so if you call GetEnumerator().Current , then the MoveNext() function has not been called on the newly returned instance! 说明: GetEnumerator()方法总是返回一个新的枚举器,因此如果调用GetEnumerator().Current ,则不会在新返回的实例上MoveNext()函数! Use a variable as stated in my second example, instead. 请使用我的第二个示例中所述的变量。

You have called MoveNext() on a different Enumerator 您已在另一个枚举器上调用了MoveNext()

your code is equivalent to 你的代码相当于

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

each time you call GetEnumerator() a new enumerator is constrcuted (at least for BCL implementations of IEnumerable ) and as you can see from the code above you construct two enumerators and call MoveNext on one and Current on the other. 每次调用GetEnumerator() ,都会构造一个新的枚举器(至少对于IEnumerable BCL实现),正如您从上面的代码中看到的那样,您构造了两个枚举器并在一个上调用MoveNext而在另一个上调用Current。 This is a key conceptual difference between properties and methods. 这是属性和方法之间的关键概念差异。 A method should be expected to return the result of an operation while a property should be expected to return the same value unless the state of the object changed. 应该期望一个方法返回一个操作的结果,而一个属性应该返回相同的值,除非该对象的状态发生了变化。 There also seems to be a logical bug in your code, you are only returning the first element and it would fail if there's none, so essentially you've implemented the .Single() method your code would work if you changed to 您的代码中似乎也存在逻辑错误,您只返回第一个元素,如果没有则会失败,所以基本上您已经实现了.Single()方法,如果您更改为

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

which of course is functionaly the same as 这当然与功能相同

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

Here you create two different enumerators. 在这里,您可以创建两个不同的枚举器。 You call MoveNext on the first , then you create another one in the line below and access Current on that. 您在第一个上调用MoveNext ,然后在下面的行中创建另一个并在其上访问Current

Another solution is, you should ensure that you return always the same Iterator when you call method GetEnumerator(). 另一种解决方案是,在调用方法GetEnumerator()时,应确保始终返回相同的迭代器。 This is the sample implementation: 这是示例实现:

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

Calling MoveNext() in the constructor is not necessary, you have to call iterator.MoveNext() method before iterator.current. 不需要在构造函数中调用MoveNext(),您必须在iterator.current之前调用iterator.MoveNext()方法。

The point is you will always use the same iterator when you call GetEnumerator() method. 关键是当您调用GetEnumerator()方法时,您将始终使用相同的迭代器。

I think you assumed that days.GetEnumerator() always returned the same enumerator. 我想你假设days.GetEnumerator()总是返回相同的枚举器。 It returns a fresh one each time for a good reason - if there was only one, different pieces of code were unable to enumerate at the same time. 它有一个很好的理由每次返回一个新的 - 如果只有一个,不同的代码片段无法同时枚举。 It would not compose well. 它组成不好。

Call days.GetEnumerator() once, or write return days.GetEnumerator(); 调用days.GetEnumerator()一次,或写入return days.GetEnumerator(); .

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

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