C# 异常如何适合抽象易失性依赖项的松散耦合设计?

C# 异常如何适合抽象易失性依赖项的松散耦合设计?,c#,exception-handling,dependencies,C#,Exception Handling,Dependencies,让我们说,不是耦合到实现代码,而是编写抽象并注入抽象的实例。例如,您可以使用存储库访问数据库: abstract class MusicRepository { public abstract IEnumerable<MusicTrack> GetTopFor(DateTime date); } class SqlMusicRespository : MusicRepository { public override IEnumerable<MusicTrac

让我们说,不是耦合到实现代码,而是编写抽象并注入抽象的实例。例如,您可以使用存储库访问数据库:

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
    }
}
抽象类音乐假定
{
公共摘要IEnumerable GetTopFor(日期时间日期);
}
SqlMusicRespository类:MusicRespository
{
公共覆盖IEnumerable GetTopFor(日期时间日期)
{
//在这里使用一些数据库对象…可能它们会引发异常
}
}
班级音乐服务
{
私有只读音乐存储库;
公共音乐服务(音乐存储库)
{
如果(repository==null)抛出新ArgumentNullException(“repository”);
this.repository=存储库;
}
公共IEnumerable GetTodaysTop()
{
//使用存储库确定跟踪内容的域逻辑
//与昨天相比,你处于(新的、上升的、下降的或相同的)位置
}
}
我不确定应该从消费代码中处理哪些异常类型,或者确切地说应该如何处理异常。实际的异常类型随着实现而变化,因此尝试处理任何特定的异常似乎是一种耦合形式

“异常适配器”应该是定义抽象的一部分吗。。。如果每个实现捕获任何异常,然后将捕获的异常作为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);
    }
}
public override IEnumerable GetTopFor(日期时间日期)
{
尝试
{
//在这里使用一些数据库对象…可能它们会引发异常
}
捕获(异常)
{
抛出新的MusicException(innerException:exception);
}
}

这似乎是从WebRequest抽象派生的.NET类型的想法。还有其他选择吗?在消费代码中为特定类型使用catch处理程序真的违反了Liskov吗?

我建议接口应该定义一组它们将产生的异常,并定义当任何其他异常逃逸时,可以或不可以对接口实现者的状态做出哪些假设。这里至少有三种可能的模式

  • 要求实现者捕获并重新标记任何不意味着实现者本身有问题的异常,以便在实现者抛出除记录的异常以外的任何异常时,可以假定实现者本身已损坏,或者
  • 要求实现者让它所使用的接口对象抛出的异常通过,除非它们损坏了实现者本身,在这种情况下,它们应该被捕获并重新命名。
  • 要求实现者捕获每个异常并将其重新命名为指示请求无法完成但实现者可能未损坏的类型、指示实现者已损坏但CPU可能未着火的类型,或者指示CPU着火的类型。 不幸的是,Microsoft现有的接口(如
    IEnumerator
    )没有记录任何这样的约定,这意味着像可枚举集合这样的东西没有明确的方式可以有意义地指示存在阻止枚举的条件,但并不意味着CPU着火(
    InvalidOperationException
    最有可能导致大多数
    IEnumerable
    使用者的行为正常,除非文档指定这意味着集合已被修改)