我有简单的代码,如果文件不存在或者其中的数据版本已过期,则意图在文件或数据库上返回枚举器。简单。但是,我正在努力解决该方法的工作原理。原因如下:
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
有关,如果是这种情况,有没有办法解决这个问题?
答案 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()..时执行...