在Single
上调用SingleOrDefault
或IEnumerable<T>
时,如果结果不只一个,则会抛出InvalidOperationException
。
尽管异常的实际消息具有很强的描述性,但是编写一个仅处理Single
/SingleOrDefault
调用失败的情况的catch是有问题的。
public virtual Fee GetFeeByPromoCode(string promoCode)
{
try
{
return _fees.SingleOrDefault(f => f.IsPromoCodeValid(promoCode));
}
catch (InvalidOperationException)
{
throw new TooManyFeesException();
}
}
在这种情况下,如果
IsPromoCodeValid
也抛出InvalidOperationException
,那么对于捕获正在处理的内容就变得模棱两可。我可以检查异常消息,但是我想避免这种情况,因为我发现根据异常消息来处理代码很脏。
我当前对
SingleOrDefault
的替代方案如下所示:public virtual Fee GetFeeByPromoCode(string promoCode)
{
var fees = _fees.Where(f => f.IsPromoCodeValid(promoCode)).ToList();
if (fees.Count > 1)
{
throw new InvalidFeeSetupException();
}
return fees.FirstOrDefault();
}
但是,此代码与上面的代码相比不那么明显,此外,与使用
SingleOrDefault
相比,此查询(如果使用启用了linq的ORM)生成的查询效率较低。我也可以在第二个示例中执行
Take(2)
来对其进行一些优化,但这进一步混淆了代码的意图。有没有一种方法,而无需为
IEnumerable
和IQueryable
编写我自己的扩展名? 最佳答案
这样可以解决问题吗?
public virtual Fee GetFeeByPromoCode(string promoCode)
{
try
{
return _fees.SingleOrDefault(f =>
{
try
{
return f.IsPromoCodeValid(promoCode);
}
catch(InvalidOperationException)
{
throw new PromoCodeException();
}
});
}
catch (InvalidOperationException)
{
throw new TooManyFeesException();
}
}