3

我正在尝试这个MSDN 页面上的示例。我试图改变GetEnumerator方法。我知道这似乎有些不对劲,但是它符合要求,然后就无法运行。错误是枚举器尚未启动,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;
    }
}
4

5 回答 5

4

为什么要调用 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()函数还没有在新返回的实例上被调用!请改用我的第二个示例中所述的变量。

于 2013-10-23T08:25:36.080 回答
3

您调用MoveNext()了不同的枚举器

你的代码相当于

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

每次调用GetEnumerator()新的枚举器时都会构造(至少对于 的 BCL 实现而言IEnumerable),并且从上面的代码中可以看出,您构造了两个枚举器并在一个上调用 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;
    }
}
于 2013-10-23T08:26:24.700 回答
1
days.GetEnumerator().MoveNext();
yield return days.GetEnumerator().Current;

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

于 2013-10-23T08:27:05.130 回答
1

另一种解决方案是,您应该确保在调用 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() 方法时,您将始终使用相同的迭代器。

于 2015-08-21T12:04:20.203 回答
0

我认为您假设days.GetEnumerator()始终返回相同的枚举数。它每次都返回一个新的有一个很好的理由 - 如果只有一个,不同的代码段无法同时枚举。它不会很好地组成。

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

于 2013-10-23T08:26:27.813 回答