我继承了一个方法,它返回一个IEnumerable<whatever>
,并通过yield return myWhatever
构造来实现:
public IEnumberable<whatever> GetWhatevers() {
while (true) {
// do calculations
yield return myWhatever
}
}
我发现了一个错误,如果类的集合之一为null,它会导致无限循环,所以我添加了一个检查并编写了一个测试:
public IEnumberable<whatever> GetWhatevers() {
if (_dependentList == null || _dependentList.Count == 0) {
throw new InvalidOperationException("Unable to process without whatevers");
}
while (true) {
// do calculations
yield return myWhatever
}
}
void MyWhateverThrowsIOEOnEmptyList() {
var sut = new MyThing(null);
Assert.ThrowsException<InvalidOperationException>(() => {
var results = sut.GetWhatevers();
});
}
我现在意识到这个测试失败了,因为即使我调用了方法(由于yield
构造),我也从未真正开始迭代结果。
我可以通过以下操作修复测试:
void MyWhateverThrowsIOEOnEmptyList() {
var sut = new MyThing(null);
Assert.ThrowsException<InvalidOperationException>(() => {
var results = sut.GetWhatevers().ToList();
});
}
但我不喜欢它。这意味着无论调用方调用这个方法,他们都不会知道,直到试图访问结果时,里面隐藏着IOE。由此产生的变量可能会往返于廷巴克图,而永远不知道这是一颗定时炸弹。
所以现在,每当我使用这个方法时,我都必须记住,其中可能潜伏着一个异常。
这个方法太复杂了,我不想用传统的循环重写。有没有一种方法可以强制在"调用时"而不是"解决时"抛出异常,这样我就可以在调用时知道存在问题?
从另一个调用迭代器方法:
public IEnumerable<Whatever> GetWhatevers(){
if (_dependentList == null || _dependentList.Count == 0) {
throw new InvalidOperationException("Unable to process without whatevers");
}
return GetWhatevers_Impl();
}
private IEnumerable<Whatever> GetWhatevers_Impl(){
while (true) {
// do calculations
yield return myWhatever
}
}