让我们说,不是耦合到实现代码,而是编写抽象并注入抽象实例。例如,您可以使用存储库访问数据库:
abstract class MusicRepository
{
public abstract IEnumerable<MusicTrack> GetTopFor(DateTime date);
}
class SqlMusicRespository : MusicRepository
{
public override IEnumerable<MusicTrack> GetTopFor(DateTime date)
{
// use some database objects here... maybe they throw an exception
}
}
class MusicService
{
private readonly MusicRepository repository;
public MusicService(MusicRepository repository)
{
if (repository == null) throw new ArgumentNullException("repository");
this.repository = repository;
}
public IEnumerable<MusicTopTrack> GetTodaysTop()
{
// domain logic that uses the repository to figure out what tracks
// are in a (new, up, down, or same) position from yesterday
}
}
我不确定应该从使用代码处理哪些异常类型,或者确切地说应该如何处理异常处理。实际的异常类型随着实现而改变,因此尝试处理任何特定似乎是一种耦合形式。
“异常适配器”是否应该成为定义抽象的一部分......每个实现都捕获任何异常,然后抛出带有捕获异常的适配器作为InnerException?
public override IEnumerable<MusicTrack> GetTopFor(DateTime date)
{
try
{
// use some database objects here... maybe they throw an exception
}
catch(Exception exception)
{
throw new MusicException(innerException: exception);
}
}
这似乎是从WebRequest抽象派生的.NET类型的想法。还有替代品吗?在消费代码中为特定类型设置一个catch处理程序是否真的违反了Liskov?
答案 0 :(得分:2)
我建议接口应该定义一组它们将产生的异常,并定义当任何其他异常转义时,可能会或可能不会对接口实现者的状态做出什么假设。这里至少有三种可能的模式
不幸的是,微软现有的接口如IEnumerator<T>
没有记录任何这样的约定,这意味着没有定义类似于可枚举集合的东西可以有意义地表明存在阻止枚举的条件但并不意味着CPU是着火(InvalidOperationException
最有可能导致大多数IEnumerable<T>
消费者的正确行为,除了文档指明它意味着集合被修改了。
答案 1 :(得分:1)
Eric Lippert撰写了一篇关于如何处理异常的优秀文章 - 建议您先阅读此内容:
http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx