3

ファイルが存在しない場合、またはファイル内のデータのバージョンが古くなっている場合に、ファイルまたはデータベースに対して列挙子を返すことを意図した単純なコードがあります。単純。しかし、私はその方法がどのように機能するかについて苦労しています。理由は次のとおりです。

public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
    try
    {
        return GetFromFiles(); // returns instantly here
    }
    catch (ArgumentOutOfRangeException)
    {
        return GetFromBackingStore();
    }
    catch (FileNotFoundException)
    {
        return GetFromBackingStore();
    }
}

GetFromFilesのようになります。

private IEnumerator<KeyValuePair<TKey, TValue>> GetFromFiles()
{
    foreach (var path in _paths)
    {
        using (var fs = _versioner.TryOpen(path))
        {
            var reader = _serializerFactory.CreateSerializer(fs, FileAccess.Read);

            KeyValuePair<TKey, TValue> pair;
            while (reader.Read(out pair))
            {
                yield return pair;
            }
        }
    }
}

ここでの問題は、GetEnumeratorforeach を使用して呼び出されると、GetFromFiles最初に呼び出しを実行せずにすぐに戻りますが、GetFromFilesメソッドに戻りますが、現在try-catchはまだ機能していないため、TryOpenスローされた場合、例外は処理されません。その理由と回避方法を理解しようとしています。それは私が思うに関連している必要がありますyield return。これが事実である場合、トリックを行う方法はありますか?

4

3 に答える 3

2

イテレータブロックの実行は延期されています。場合によっては、イテレータブロックの中央部分をリファクタリング(「抽出メソッド」)できるため、コアテストをすぐに実行し、反復を延期するだけですが、外部foreach(特に、すべてを開かない限り、最初のファイルを実際に先制的にチェックすることしかできませんでした)。

サイズが中程度の場合、おそらく最も簡単なことは、.ToList()今すぐすべてを追加することです。

return GetFromFiles().ToList();
于 2012-11-24T07:21:50.053 に答える
2

try / catchを含む最初のメソッドは2番目のメソッドへの参照を返すため、呼び出されるのは1回だけです。外部コードが列挙するたびに、最初のメソッドは既に列挙子への参照を持っているため、最初のメソッドを再度呼び出すことはありません。したがって、外部コードは直接呼び出します。try / catchを2番目のメソッドに移動するか、要素を一度に1つずつ読み取るのではなく、すべてを一度に初期化する標準のコレクションを使用する必要があります。お役に立てれば。

于 2012-11-24T07:22:11.567 に答える
2

答えはyeild演算子にあり、try catch 内の列挙子は実行されませんでした。この部分:

{ return GetFromFiles(); を試してください。// ただの約束 }

Enumerator をpromiseとして返しています。に対してまだ実行された明示的な反復はありませんでしたIEnumerable<>。利回りは先物として機能します。後で .ToList() または .Count() が呼び出されたときに実行されます...

于 2012-11-24T07:23:22.693 に答える