2013-10-23 42 views
3

我试着在这个MSDN page上的例子。我试图改变GetEnumerator方法。我知道这件事看起来不太合适,但它遵守,然后不运行。错误在于枚举器尚未启动,应该调用MoveNext,但调用时它是为什么以下不工作? (IEnumerable/IEnumerator)

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

回答

3

为什么要调用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()功能还没有被新近返回的实例调用!改为使用第二个示例中所述的变量。

3

你叫MoveNext()在不同的枚举

你的代码就相当于

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

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

public IEnumerator GetEnumerator() 
{ 
    var enumerator = days.GetEnumerator(); 
    while(enumerator.MoveNext()){ 
     yield return enumerator.Current; 
    } 
} 
您的代码会工作

这当然是functionaly一样

public IEnumerator GetEnumerator() 
{ 
    foreach(var day in days){ 
     yield return day; 
    } 
} 
0

我想你认为days.GetEnumerator()总是返回相同的枚举。每当有一个很好的理由时,它会返回一个新的 - 如果只有一个,则不同的代码片段不能同时枚举。它不会构成好。

致电days.GetEnumerator()一次,或写return days.GetEnumerator();

1
days.GetEnumerator().MoveNext(); 
yield return days.GetEnumerator().Current; 

在这里,您创建两个不同枚举。您拨打MoveNext,首先,然后您在下面创建另一个并访问Current就可以了。

1

另一种解决方案是,您应确保在调用方法GetEnumerator()时始终返回相同的Iterator。这是简单的实现:

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()方法时,您将始终使用相同的迭代器。