在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))
{
}
}
我不知道是否会编译。
执行此操作的标准方法是什么?
答案 0 :(得分:9)
public virtual string Message
Message是虚拟的 - 因此您可以在课堂上轻松覆盖它。
public class OPCCaException : Exception
{...
public override string Message
{
get { return "My fancy text";}
}
}
更标准的方法是通过调用将消息传递给基类构造函数:
public OPCCaException(...) : base(buildMessage(...))
{
}
答案 1 :(得分:4)
为什么异常消息属性是只读的?
因为异常意味着在向上移动堆栈跟踪时保持不变。如果在捕获时想要提供更多信息/有意义的消息,则应将捕获的异常包装在另一个异常中。有constructor就是这样。
在我看来,这是一个非常合理的事情,但它不会编译,因为Message属性是只读的。
你想要达到的目标是完全合理的。你试图实现的方式不是。由于Message属性是只读的,因此任何人都可以为其分配任何内容,包括您。出于这个原因,它被虚拟化了。阅读更多有关在MSDN上覆盖它的信息。
答案 2 :(得分: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)
);
}
}
}
答案 3 :(得分:3)
您是否注意到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;
}
}