0

什么时候创建一个新的例外是合理的。在针对 .Net 框架制定新的异常类型是一个好的设计决策之前,是否有某种清单需要满足条件?

例如考虑:

您有一个带有方法的类,该方法返回一个整数,该整数对于方法的使用者来说并不重要,但会提供一些额外的信息。该方法中可能出现的各种错误并不取决于类的用户如何调用此方法。假设一个是网络连接可能丢失,另一个是该方法试图调用的 Web 服务的 API 发生了变化。该方法的使用者没有能力以不同的方式处理这些情况以尝试从异常中恢复。这些操作是否应该有两个不同的例外或更一般的例外(例如CommunicationFailureException) 用特定的描述和内部异常覆盖这两种情况?还是应该抛出最初在方法调用 Web 服务失败时抛出的 .Net 异常?

我希望更多地了解创建新异常类型的原则,而不是仅仅涵盖这个特定示例。

4

6 回答 6

2

当您有关于异常的其他内容时创建一个新的异常类型 - 现有异常未涵盖的内容。

如果您的应用程序有一些特定的不变量并且您需要传达它们是无效的 - 这可能是自定义异常类型的好地方。这允许您捕获特定于您的应用程序的异常。

于 2012-05-18T09:56:02.090 回答
1

I think it makes sense to create custom exceptions in two cases.

  1. If you need to add more information to the exception.

  2. If there is a possibility that the caller of your exception will need to catch that particular exception and handle it differently.

Otherwise, it's best to use the standard exception classes.

于 2012-05-18T09:57:45.313 回答
0

.Net 框架没有提供任何方法来让调用方法的例程Foo可以区分由 抛出的异常和由以意想不到且未处理Foo的方式调用的方法抛出的异常。可能会提供线索,但由于像内联这样的优化,它并不完全可靠。FooFooStackTrace

因此,如果Foo要抛出任何应该对其调用者有意义的异常,它应该确保任何逃逸类型的异常实际上都具有该含义。请注意,.Net 框架在这方面有些不足;例如,如果在枚举期间修改了集合IEnumerator.MoveNext()InvalidOperationException则应该抛出如果从调用的例程MoveNext()由于某些其他原因抛出这样的异常。

使用自定义异常通常是避免此类问题的好方法。如果您从您的例程中抛出一个不会出于任何其他目的而抛出的异常,那么捕获它的代码可以确定该异常意味着它认为它意味着什么。

于 2012-05-19T18:56:57.273 回答
0

奥德提出了一个很好的观点。

我认为可以在本主题中添加的是对 API 的抽象。您需要创建一个异常包装器,为所有实现提供通用合同。我知道它已被 oded 的响应所涵盖,但我认为可以指出:

void Main()
{
    try
    {
        IUserRepository = //assume that IoC container provides specific implementation
    }
    catch (UserNotFoundException e)
    {
        Console.WriteLine(string.Format("User not found: {0}", e.Id));
    }
}


class User
{
    public int Id {get;set;}
}

class UserNotFoundException : Exception
{
    public int Id {get;private set;}

    public UserNotFoundException(int id, Exception innerException)
        :base(string.Format("User {0} could not be found", id), innerException)
    {
        Id = id;
    }
}

interface IUserRepository
{
    User GetUser(int id);
}

class XmlUserRepository : IUserRepository
{
    string _path;

    public XmlUserRepository(string path)
    {
        _path = path;
    }

    public User GetUser(int id)
    {
        try
        {
            //retrieving code that might throw IOException or XmlException
        }
        catch (Exception e)
        {
            //catching Exception is not a good thing to do, but for the sake of clarity I made this like that
            throw new UserNotFoundException(id, e);
        }
    }
}

class DbUserRepository : IUserRepository
{
    string _dbConnectionString;

    public DbUserRepository(string dbConnectionString)
    {
        _dbConnectionString = dbConnectionString;
    }

    public User GetUser(int id)
    {
        try
        {
            //retrieving code that might throw SqlException
        }
        catch (Exception e)
        {
            //catching Exception is not a good thing to do, but for the sake of clarity I made this like that
            throw new UserNotFoundException(id, e);
        }
    }
}
于 2012-05-22T06:12:25.333 回答
0

这篇文章给出了一些很好的指导。

特别是声明的部分:

如果它们没有对客户端代码有用的信息,请尽量不要创建新的自定义异常。

于 2012-05-18T09:56:17.977 回答
0

您可以查看此页面以获取一个小清单:http ://docs.oracle.com/javase/tutorial/essential/exceptions/creating.html

该站点适用于 Java,但概念是相同的。

于 2012-05-18T09:56:37.667 回答