如何解决GetEnumerator推迟的电话?

时间:2012-11-24 07:12:57

标签: c# .net collections

我有简单的代码,如果文件不存在或者其中的数据版本已过期,则意图在文件或数据库上返回枚举器。简单。但是,我正在努力解决该方法的工作原理。原因如下:

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

现在的问题是,当使用foreach调用GetEnumerator时,它会立即返回,而不会先执行GetFromFiles调用,但它会返回到GetFromFiles方法但现在try-catch已经没有使用,所以如果TryOpen抛出,则不处理异常。我试图理解为什么以及如何解决它。它必须与我认为的yield return有关,如果是这种情况,有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:2)

迭代器块具有延迟执行。在某些情况下,您可以重构(“提取方法”)迭代器块的中心部分,因此您可以立即执行核心测试并且只推迟迭代,但这不可能,因为您正在执行外部foreach (特别是,除非你全部打开它们,否则你只能先用力先检查第一个文件。)

如果尺寸适中,最简单的事情就是添加.ToList()来完成整个事情:

return GetFromFiles().ToList();

答案 1 :(得分:2)

你拥有的第一个方法,包括try / catch,返回对第二个方法的引用,所以它只被调用一次。每次外部代码枚举时,它都不会再次调用第一个方法,因为它已经引用了枚举器,因此它直接调用它。您需要将try / catch移动到第二个方法,或者使用一次性初始化的标准集合,而不是一次读取一个元素。希望这会有所帮助。

答案 2 :(得分:2)

答案在yeild运算符中,而try catch内部的枚举数未执行。这部分:

试 {     return GetFromFiles(); //只是一个承诺 }

将Enumerator作为承诺返回。在IEnumerable<>上没有执行明确的迭代。产量充当 future 。它将在稍后调用.ToList()或.Count()..时执行...