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

现在的问题是,当GetEnumerator使用 foreach 调用时,它会立即返回而无需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)返回对第二个方法的引用,因此它只被调用一次。每次外层代码枚举通过时,不会再调用第一个方法,因为它已经引用了枚举器,因此直接调用它。您需要将 try/catch 移动到第二种方法,或者使用一个标准集合来初始化一次,而不是一次读取一个元素。希望这可以帮助。

于 2012-11-24T07:22:11.567 回答
2

答案在yeild操作符中,而 try catch 内部的枚举器未执行。这部分:

尝试 { 返回 GetFromFiles(); // 只是一个承诺 }

将 Enumerator 作为promise返回。还没有执行显式迭代IEnumerable<>。收益率充当未来。稍后将在调用 .ToList() 或 .Count() .. 时执行...

于 2012-11-24T07:23:22.693 回答