5

也许 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))
    {
    }
 }

我不知道这是否会编译。

执行此操作的标准方法是什么?

4

4 回答 4

9

public virtual string Message

消息是虚拟的 - 因此您可以在课堂上轻松地覆盖它。

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

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

public OPCCaException(...) : base(buildMessage(...))
{
}
于 2013-03-07T20:22:04.183 回答
4

Why is the exception message property read only?

Because exceptions are meant to stay intact as they travel up the stack trace. If, as you capture, you want to provide more information/meaningful message you should wrap the captured exception in another exception. There is a constructor that does exactly that.

This seems to me to be a perfectly reasonable thing to do, but it won't compile because the Message property is read-only.

What you're trying to achieve is perfectly reasonable. The way you're trying to achieve is not. Since Message property is read-only nobody can assign anything to it, including you. For this reason it was made virtual. Read more about overriding it on MSDN.

于 2013-03-07T20:28:23.937 回答
3

您可以将消息传递给基类构造函数,也可以覆盖类的 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)
             );
        }
    }
}
于 2013-03-07T20:23:56.200 回答
2

你注意到这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;
    }
}
于 2013-03-07T20:24:47.197 回答