为什么异常消息属性是只读的

本文关键字:只读 属性 异常 消息 为什么 | 更新日期: 2023-09-27 18:02:44

也许c#中最让我困惑的事情是Exception类的message属性是只读的。可能是因为我不理解其中的原因,当我试图创建从exception派生的合理异常类时,我感到很沮丧。

例如(实际上我正在尝试做什么),我想创建一个异常,当尝试连接到OPC服务器时引发。如果尝试失败,则会引发OPCException类型的对象,但我想给用户更多信息。因此,我有一个名为OPCCaException的类,它接受三个参数:原始异常的返回代码、服务器名和主机名。

public class OPCCaException : Exception
{
    public OPCCaException(ReturnCode returnCode, string serverName, string nodeName)
    {
        if (nodeName == "")
        {
            this.Message = "Failed to connect to OPC server "+ serverName + 
                           ": " + TranslateReturnCode()";
        }
        else
        {
            this.Message = "Failed to connect to OPC server "+ serverName + 
                           " on node " + nodeName +
                           ": " + TranslateReturnCode()";
        }
    }
}

这对我来说似乎是一个完全合理的事情,但它不会编译,因为Message属性是只读的。设置消息的唯一方法是将其传递给基类构造函数。为什么我不能在派生类的构造函数中设置它?我能想到的对参数进行任何处理的唯一方法是创建一个静态类来构建消息:

public class OPCCaException : Exception
{
    private static string BuildMessage(<some arguments>)
    {
        string message = "some message";
        return message;
    }
    public OPCCaException(ReturnCode returnCode, string serverName, string nodeName) :
        base(BuildMessage(returnCode, serverName, nodeName))
    {
    }
 }

我不知道这是否可以编译。

这样做的标准方法是什么?

为什么异常消息属性是只读的

public virtual string Message

Message是虚拟的——所以你可以很容易地在你的类中重写它。

public class OPCCaException : Exception
{...
  public override string Message 
  {
    get { return "My fancy text";}
  }
}

另一种更标准的方法是通过调用基类构造函数传递消息:

public OPCCaException(...) : base(buildMessage(...))
{
}

为什么异常消息属性是只读的?

因为异常在堆栈跟踪中保持完整。如果在捕获时希望提供更多信息/有意义的消息,则应该将捕获的异常包装在另一个异常中。有一个构造函数就是这样做的。

这对我来说似乎是一个完全合理的事情,但它不会编译,因为Message属性是只读的。

你想达到的目标是完全合理的。你努力实现目标的方式不是。因为Message属性是只读的,没有人可以给它分配任何东西,包括你。因此,它是虚拟的。阅读更多关于在MSDN上重写它的信息。

您可以将消息传递给基类构造函数,也可以重写类上的message属性以返回其他内容。例如:

public class OPCCaException : Exception
{
    ReturnCode returnCode;
    string serverName;
    string nodeName;
    public OPCCaException(ReturnCode returnCode, string serverName, string nodeName)
        : base();
    {
         this.returnCode = returnCode;
         this.serverName = serverName;
         this.nodeName = nodeName;
    }
    public override string Message
    {
        get
        {
             return string.Format("Failed to connect to OPC server {0}{1}: {2}",
                 serverName, 
                 string.IsNullOrEmpty(nodeName ? "" : " on node " + nodeName),
                 TranslateReturnCode(returnCode)
             );
        }
    }
}

您注意到Exception.Message是一个虚拟属性了吗?处理此问题的适当方法是覆盖Message并提供您自己的实现

public class MyException : Exception
{
    private string myMessage = null;
    public override string Message
    {
        get
        { 
            return String.IsNullOrEmpty(myMessage) ? 
                 base.Message : 
                 myMessage; 
        }
    }
    public MyException(string message) : base()
    {
        myMessage = message;
    }
}