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().CurrentMoveNext()新しく返されたインスタンスで関数が呼び出されていません! 代わりに、2 番目の例で述べたように変数を使用してください。

于 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場合)、上記のコードからわかるように、2 つの列挙子を構築し、一方では 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

もう 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() メソッドを呼び出すときに常に同じ反復子を使用することです。

于 2015-08-21T12:04:20.203 に答える
1
days.GetEnumerator().MoveNext();
yield return days.GetEnumerator().Current;

ここでは、2 つの異なる列挙子を作成します。最初の を呼び出しMoveNextてから、下の行に別のものを作成し、それにアクセスします。Current

于 2013-10-23T08:27:05.130 に答える
0

days.GetEnumerator()常に同じ列挙子を返すと仮定したと思います。正当な理由で毎回新しいものを返します.1つしかない場合、異なるコードが同時に列挙できませんでした. それはうまく構成できません。

days.GetEnumerator()一度呼び出すか、または書き込みreturn days.GetEnumerator();ます。

于 2013-10-23T08:26:27.813 に答える