Maybe the most mystifying thing to me in C# is that the Exception class's message property is read-only. Probably because I don't understand the reason for this, I am frustrated when I try to create reasonable exception classes derived from Exception.
For example (and actually what I'm trying to do), I want to create an exception to raise when an attempt to connect to an OPC server. An object of type OPCException is raised if the attempt fails, but I want to give the user more information. So, I have a class named OPCCaException that takes three arguments: the return code from the original exception, the server name, and the host name.
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()";
}
}
}
This seems to me to be a perfectly reasonable thing to do, but it won't compile because the Message property is read-only. The only way to set the message is to pass it to the base class constructor. Why can't I set it in my derived class's constructor? The only way I can think of to do any kind of processing on the arguments is to create a static class to build the 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))
{
}
}
I don't know if that will compile.
What is the standard way to do this?
C# provides built-in support to handle the exception using try , catch & finally blocks. try block: Any suspected code that may raise exceptions should be put inside a try{ } block. During the execution, if an exception occurs, the flow of the control jumps to the first matching catch block.
Property Value The InnerException property returns the same value as was passed into the Exception(String, Exception) constructor, or null if the inner exception value was not supplied to the constructor.
The readOnly property sets or returns whether a text field is read-only, or not. A read-only field cannot be modified. However, a user can tab to it, highlight it, and copy the text from it. Tip: To prevent the user from interacting with the field, use the disabled property instead.
In my experience, when it comes to writing exception messages, most developers approach the job with one of these mindsets: Write the shortest possible exception message; if possible, ignore good grammar, punctuation, and proper spelling. Write lovingly crafted error messages for the end users.
public virtual string Message
Message is virtual - so you can easily override it in your class.
public class OPCCaException : Exception
{...
public override string Message
{
get { return "My fancy text";}
}
}
Also more standard way of doing it is to pass message via call to base class constructor:
public OPCCaException(...) : base(buildMessage(...))
{
}
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.
You can either pass the message to the base class constructor, or you can override the Message property on your class to return something else. For example:
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)
);
}
}
}
Have you noticed that Exception.Message
is a virtual property? The appropriate way to handle this would be to override Message
and provide your own implementation
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With