c# - 构造函数重载异常

标签 c# inheritance exception

在 C# 中创建自定义 Exception 类型时,为什么重载所有这些构造函数被认为是良好实践:

Exception()
Exception(String)
Exception(String, Exception)

参见: https://learn.microsoft.com/en-us/dotnet/standard/exceptions/best-practices-for-exceptions#include-three-constructors-in-custom-exception-classes

我在这些建议中都没有看到任何具体的理由。

如果我想创建一个自定义Exception,如果调用另一个系统发生未知错误,则应抛出该异常,如果我只需要信息,为什么在这里覆盖其他构造函数被认为是好的关于发生故障的系统以及导致该故障的操作:

public class ExternalSystemCallException : Exception {
    public string FailedSystem { get; }
    public string OperationName { get; }

    public ExternalSystemCallFailedException(string failedSystem, string operationName) {
        FailedSystem = failedSystem;
        OperationName = operationName;
    }
}

免责声明:我知道我可以在此处传递其他信息,因此这只是一个相当简单的示例。

更新1:

据我了解,我将覆盖所有构造函数,但同时添加异常所需的所有参数。这是正确的吗?

示例:

Exception(string failedSystem, string operationName) 
    : base()

Exception(string failedSystem, string operationName, string message) 
    : base(message)

Exception(string failedSystem, string operationName, string message, Exception innerException) 
    : base(message, innerException)

最佳答案

因为 MessageInnerException 属性在 Exception 类上都是只读的。这意味着设置它们的唯一方法是通过构造函数。您的实现不允许设置这些属性,因为您省略了相关的构造函数。这意味着你的异常(exception):

  1. 丢失导致该异常的另一个异常中包含的有值(value)的信息(如果有)。它的 InnerException 始终为 null。

  2. 在记录或向用户显示时不显示人类可读的信息。记录异常时 - 仅考虑 Exception 基类的属性,例如 MessageInnerException。对于您的异常,这些属性始终为 null,因此只有堆栈跟踪(甚至不完整)会出现在日志中(您的 FailedSystem 和 OperationsName 也不会出现在那里) .

您可能认为代码的用户会捕获特定的 ExternalSystemCallException 异常,然后根据其属性采取行动,但这并不是经常发生的情况。您的代码可能会用作较大操作的一部分,然后堆栈上会有一些包罗万象的处理程序,它只会记录异常并向用户显示一些错误消息。因此,将基本 Exception 属性设置为有意义的值非常重要。

要“修复”您的异常类型,您可以考虑执行以下操作:

public class ExternalSystemCallException : Exception
{
    public string FailedSystem { get; }
    public string OperationName { get; }

    public ExternalSystemCallException(
             string failedSystem, 
             string operationName, 
             Exception innerException = null)
            : base($"Operation {operationName} failed in {failedSystem}", innerException) {
        FailedSystem = failedSystem;
        OperationName = operationName;
    }        
}

这样,您始终将 Message 设置为有意义的值,并允许在需要时传递 InnerException。如果在不提供系统和操作名称值的情况下抛出类型的异常没有意义,则可以省略空的 Exception 构造函数。

关于c# - 构造函数重载异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48808562/

相关文章:

c++ - 为什么在异常掩码未设置为 eofbit 时 getline() 抛出 'std::ios_base::failure'?

node.js - 在 NodeJS 中优雅地处理子进程中的错误

c# - java 中 C# System.Windows.Forms.SendKeys.Send 方法的替代方法

C#面板不可见

python - 从python中的父类(super class)获取属性

exception - 有没有办法自定义 Active Directory 异常/错误消息?

c# - 我可以限制进程的 RAM 使用量吗?

c# - 动态向 DataTable 添加行

ruby-on-rails - 在哪里找到多个 Rails Controller 使用的方法并限制对基本 Controller 的访问

javascript - 使用函数构造函数的原型(prototype)继承