Should exceptions contain dynamic data? - c#

I have such method:
public function someMethod($param1 = null, $param2 = null)
{
...
if ($param1 == null &&...)
{
throw new Exception("Some parameter is wrong", 601);
}
}
Is it a good practice to include dynamic data in the Exception msg, since I have the exception code ? For example the exception could look like this:
throw new Exception("First parameter is wrong. You passed: {$param1}", 601);
What is your opinion, is it okey messages to be dynamic or I should stick to fixed text for the Exception messages ?

Should exceptions contain dynamic data?
Should? No. but they can! but be sure that "generating" this dynamic data will not cause another exception.
But you should never throw new Exception(). Extend it for your own custom exceptions or use javas exceptions like IllegalArgumentException

Related

uplifitng return value error reporting to Exceptions

In Framework Design guideline book there is a chapter about Exception and they talk about return-value-based error reporting and exception based error reporting and the fact that we in a O.O language like C# we should avoid return-value-based error reporting and use exceptions. With that in mind I was looking at our code that eight years ago was written in Visual Basic and last year with a automatic tool got converted to C#!
So here is a method I am looking at, I was wondering if the advice from that book applies to such a method and if yes, then what would be a better approach for rewriting this method?
public int Update(CaseStep oCaseStepIn)
{
int result = 0;
//Update the master object with the passed in object
result = UCommonIndep.gnUPDATE_FAILED;
if (Validate(oCaseStepIn) == UCommonIndep.gnVALIDATE_FAILED)
{
return result;
}
CaseStep oCaseStep = get_ItemByObjectKey(oCaseStepIn.CopyOfObjectKey);
if (oCaseStep == null)
{
return result;
}
return result;
}
Throw specific exceptions when possible. Then, you don't need a return value in this case.
public void Update(CaseStep oCaseStepIn)
{
//Update the master object with the passed in object
if (Validate(oCaseStepIn) == UCommonIndep.gnVALIDATE_FAILED)
throw new ValidationFailedUpdateException();
CaseStep oCaseStep = get_ItemByObjectKey(oCaseStepIn.CopyOfObjectKey);
if (oCaseStep == null)
throw new KeyObjectNotFoundUpdateException();
if (oCaseStep.Update(oCaseStepIn) != UCommonIndep.gnUPDATE_SUCCESSFUL)
throw new UpdateFailedException();
//*******************************
//FYI - Insert code here to update any Key values that might have changed.
}
UpdateFailedException extends Exception
ValidationFailedUpdateException extends UpdateFailedException
KeyObjectNotFoundUpdateException extends UpdateFailedException
There are (at least) as many opinions on exception handling as there are coders, but a good rule of thumb to start from is that exceptions should be thrown in exceptional circumstances.
So, is an update failure an exceptional occurrence?

How to catch the original (inner) exception in C#?

i'm calling a function that throws a custom exception:
GetLockOwnerInfo(...)
This function in turn is calling a function that throws an exception:
GetLockOwnerInfo(...)
ExecuteReader(...)
This function in turn is calling a function that throws an exception:
GetLockOwnerInfo(...)
ExecuteReader(...)
ExecuteReader(...)
And so on:
GetLockOwnerInfo(...)
ExecuteReader(...)
ExecuteReader(...)
ExecuteReaderClient(...)
Fill(...)
One of these functions throws an SqlException, although that code has no idea what an SqlException is.
Higher levels wrap that SqlException into another BusinessRuleException in order to include some special properties and additional details, while including the "original" exception as InnerException:
catch (DbException ex)
{
BusinessRuleExcpetion e = new BusinessRuleException(ex)
...
throw e;
}
Higher levels wrap that BusinessRuleException into another LockerException in order to include some special properties and additional details, while including the "original" exception as InnerException:
catch (BusinessRuleException ex)
{
LockerException e = new LockerException(ex)
...
throw e;
}
The problem now is that i want to catch the origianl SqlException, to check for a particular error code.
But there's no way to "catch the inner exception":
try
{
DoSomething();
}
catch (SqlException e)
{
if (e.Number = 247)
{
return "Someone";
}
else
throw;
}
i thought about catching SqlException right when it's thrown, and copy various values to the re-thrown exception - but that code is not dependant on Sql. It is experiencing an SqlException, but it has no dependency on SqlException.
i thought about catching all exceptions:
try
{
DoSomething(...);
}
catch (Exception e)
{
SqlException ex = HuntAroundForAnSqlException(e);
if (ex != null)
{
if (e.Number = 247)
{
return "Someone";
}
else
throw;
}
else
throw;
}
But that's horrible code.
Given that .NET does not let you alter the Message of an Exception to include additional information, what is the intended mechanism to catch original exceptions?
You need c# 6 / visual studio 2015 in order to do this using a predicate:
catch (ArgumentException e) when (e.ParamName == “…”)
{
}
Official C# Try/Catch Documentation
I hate to have to tell you this, but you cannot catch an inner exception.
What you can do is inspect one.
I suggest you catch your high-level exception (I believe it was LockerException) and inspect the InnerException property of that exception. Check the type, and if it's not a SqlException, check the InnerException of that exception. Walk each one until you find a SqlException type, then get the data you need.
That said, I agree with dasblinkenlight that you should consider -- if possible -- a heavy refactor of your exception framework.
Checking the error code of a wrapped exception is not a good practice, because it hurts encapsulation rather severely. Imagine at some point rewriting the logic to read from a non-SQL source, say, a web service. It would throw something other than SQLException under the same condition, and your outer code would have no way to detect it.
You should add code to the block catching SQLException to check for e.Number = 247 right then and there, and throw BusinessRuleException with some property that differentiates it from BusinessRuleException thrown in response to non-SQLException and SQLException with e.Number != 247 in some meaningful way. For example, if the magic number 247 means you've encountered a duplicate (a pure speculation on my part at this point), you could do something like this:
catch (SQLException e) {
var toThrow = new BusinessRuleException(e);
if (e.Number == 247) {
toThrow.DuplicateDetected = true;
}
throw toThrow;
}
When you catch BusinessRuleException later, you can check its DuplicateDetected property, and act accordingly.
EDIT 1 (in response to the comment that the DB-reading code cannot check for SQLException)
You can also change your BusinessRuleException to check for SQLException in its constructor, like this:
public BusinessRuleException(Exception inner)
: base(inner) {
SetDuplicateDetectedFlag(inner);
}
public BusinessRuleException(string message, Exception inner)
: base(message, inner) {
SetDuplicateDetectedFlag(inner);
}
private void SetDuplicateDetectedFlag(Exception inner) {
var innerSql = inner as SqlException;
DuplicateDetected = innerSql != null && innerSql.Number == 247;
}
This is less desirable, because it breaks encapsulation, but at least it does it in a single place. If you need to examine other types of exceptions (e.g. because you've added a web service source), you could add it to the SetDuplicateDetectedFlag method, and everything would work again.
Having an outer application layer care about the details of a wrapped exception is a code smell; the deeper the wrapping, the bigger the smell. The class which you now have wrapping the SqlException into a dbException is presumably designed to expose an SqlClient as a generic database interface. As such, that class should include a means of distinguishing different exceptional conditions. It may, for example, define a dbTimeoutWaitingForLockException and decide to throw it when it catches an SqlException and determines based upon its error code that there was a lock timeout. In vb.net, it might be cleaner to have a dbException type which exposes an ErrorCause enumeration, so one could then say Catch Ex as dbException When ex.Cause = dbErrorCauses.LockTimeout, but unfortunately exception filters are not usable in C#.
If one has a situation where the inner-class wrapper won't know enough about what it's doing to know how it should map exceptions, it may be helpful to have the inner-class method accept an exception-wrapping delegate which would take an exception the inner class has caught or would "like" to throw, and wrap it in a way appropriate to the outer class. Such an approach would likely be overkill in cases where the inner class is called directly from the outer class, but can be useful if there are intermediate classes involved.
Good question and good answers!
I just want to supplement the answers already given with some further thoughts:
On one hand I agree with dasblinkenlight and the other users. If you catch one exception to rethrow an exception of a different type with the original exception set as the inner exception then you should do this for no other reason than to maintain the method's contract. (Accessing the SQL server is an implementation detail that the caller is not/must not/cannot be aware of, so it cannot anticipate that a SqlException (or DbException for that matter) will be thrown.)
Applying this technique however has some implications that one should be aware of:
You are concealing the root cause of the error. In your example you are reporting to the caller that a business rule was invalid(?), violated(?) etc., when in fact there was a problem accessing the DB (which would be immediately clear if the DbException were allowed to bubble up the call stack further).
You are concealing the location where the error originally occurred. The StackTrace property of the caught exception will point to a catch-block far away from the location the error originally occurred. This can make debugging notoriously difficult unless you take
great care to log the stack traces of all the inner exceptions as well. (This is especially true once the software has been deployed into production and you have no means to attach a
debugger...)
Given that .NET does not let you alter the Message of an Exception to include additional information, what is the intended mechanism to catch original exceptions?
It is true that .NET does not allow you to alter the Message of an Exception. It provides another mechanism however to supply additional information to an Exception via the Exception.Data dictionary. So if all you want to do is add additional data to an exception, then there is no reason to wrap the original exception and throw a new one. Instead just do:
public void DoStuff(String filename)
{
try {
// Some file I/O here...
}
catch (IOException ex) {
// Add filename to the IOException
ex.Data.Add("Filename", filename);
// Send the exception along its way
throw;
}
}
As other peeps say, you cannot catch an the InnerException. A function such as this could help you get the InnerException out of the tree though:
public static bool TryFindInnerException<T>(Exception top, out T foundException) where T : Exception
{
if (top == null)
{
foundException = null;
return false;
}
Console.WriteLine(top.GetType());
if (typeof(T) == top.GetType())
{
foundException = (T)top;
return true;
}
return TryFindInnerException<T>(top.InnerException, out foundException);
}
I agree with the other comments that this is a code smell 🦨 and should be avoided. But if a refactor is not possible you could try something like this...
Create an extension method...
public static bool HasInnerException(this Exception ex, Func<Exception, bool> match)
{
if (ex.InnerException == null)
{
return false;
}
return match(ex.InnerException) || HasInnerException(ex.InnerException, match);
}
And use it like...
catch (Exception ex) when (ex.HasInnerException(e => e is MyExceptionThatIsHidden))
{
...
But really you should be solving for 👇
var exception = new Exception("wrapped exception 3",
new Exception("wrapped exception 2",
new Exception("wrapped exception 1",
new MyExceptionThatIsHidden("original exception")))); // <--- ???

Exception with null message

I found that exception message can't be null in C#, and after trying this
var ex = new Exception(null);
Console.WriteLine(ex.Message);
I get the following message:
Exception of type 'System.Exception' was thrown.
But, in this case,
var ex = new Exception(string.Empty);
Console.WriteLine(ex.Message);
the message is just empty.
How this can be explained? Do you think this is expected behavior?
The other answers (not including the answer from chopikadze) seem to be based on a misreading of the facts. Neither example is throwing an exception.
Rather, in the first example, the constructed exception ex is providing a message because the value of the constructor's message parameter was null. The message is "an exception of type 'System.Exception' was thrown".
It's a fairly common practice to have some fallback behavior when an object reference is null, so that's "how it can be explained". Whether it is "expected", of course, depends on your expectations.
Throwing exceptions in the course of handling exceptions can be problematic, so the framework designers must have chosen this behavior to reduce this possibility. It would have been a nightmare, frankly, if we all had to cover the possibility that exception messages might be null.
EDIT
The behavior is also documented in the remarks for the Message property: "If no message was supplied to the constructor for the current instance, the system supplies a default message that is formatted using the current system culture."
I looked in the CLI spec and in the C# spec, and I found no mention of a requirement that Message have a non-null return value, so I guess that supports the view that this behavior is a framework design decision.
Actually constructor doesn't need string, you can absolutely surely use null. This is reflectored part of Exception class:
internal string _message;
public Exception(string message)
{
this.Init();
this._message = message;
}
private void Init()
{
this._message = null;
this._stackTrace = null;
this._dynamicMethods = null;
this.HResult = -2146233088;
this._xcode = -532462766;
this._xptrs = IntPtr.Zero;
this._watsonBuckets = null;
this._ipForWatsonBuckets = UIntPtr.Zero;
this._safeSerializationManager = new SafeSerializationManager();
}
public virtual string Message
{
[SecuritySafeCritical]
get
{
if (this._message != null)
{
return this._message;
}
if (this._className == null)
{
this._className = this.GetClassName();
}
return Environment.GetRuntimeResourceString("Exception_WasThrown", new object[] { this._className });
}
}
So if you use null as message in constructor, localized string like "Exception of type 'System.Exception' was thrown." will be used as Message. It means - there is still your Exception, not another one, but it's property Message returns another (calculated) value instead of null from constructor.
I think that it's defined by design (and maybe is used in another places) that Exception.Message should be always not null. So if we want to allow developers use default constructor for Exception class (for example, for using with reflection or for allowing to populate properties later) but we also want to has Message always not null - we should wrap Message with something. I think, one of the possible place of Message usage is default dialog box showed after exception occurs. This way there could be used just Message property, instead of checking - is Message property equals to null etc.
string.Empty is not null it is a constant for "".
Your first example is giving a default message, your second example is an empty string
Yes, the constructor you are using requires a string. String.Empty is not the same as null therefore it will throw an exception.
http://msdn.microsoft.com/en-us/library/system.exception.aspx

Constructors and throwing exceptions

Is this the best way for me to abort instantiation of an object if it's parameters are not passed in with valid data?
protected Command(string commandKey)
{
if(commandKey == null) throw new ArgumentNullException("commandKey", "Command Key cannot be null as it is required internally by Command");
if(commandKey == "") throw new ArgumentException("Command Key cannot be an empty string");
CommandKey = commandKey;
}
Yes. It is common practice to validate the arguments in constructors and throw an exception if they are invalid.
It's perfectly fine. Constructors do not return anything so how else would you know if something went wrong? You could have a bool to set it to some uninitialized state but I would go with exceptions.
Also :
if(String.IsNullOrEmpty(commandKey)) //throw exectpion
In this case you could use the static method string.IsNullOrEmpty(commandKey):
protected Command(string commandKey)
{
if(string.IsNullOrEmpty(commandKey))
throw new ArgumentException("commandKey");
//something
}
This is exactly what Microsoft does if you look through the framework source code, so I suspect it is perfectly valid.
It is perfectly fine if you validate inside a constructor and throw exception if something goes wrong.

if statement for throwing Exception?

Hi I wanted to ask because I'm not sure if is it propriete using of Exception:
public int Method(int a, int b) {
if(a<b) throw new ArgumentException("the first argument cannot be less than the second");
//do stuff...
}
can I throw Exception after if statement? or should I always use try - catch when it goes with the exceptions?
That is perfectly valid. That is exactly what exceptions are used for, to check for "Exceptions" in your logic, things that weren't suppose to be.
The idea behind catching an exception is that when you pass data somewhere and process it, you might not always know if the result will be valid, that is when you want to catch.
Regarding your method, you don't want to catch inside Method but infact when you call it, here's an example:
try
{
var a = 10;
var b = 100;
var result = Method(a, b);
}
catch(ArgumentException ex)
{
// Report this back to the user interface in a nice way
}
In the above case, a is less than b so you can except to get an exception here, and you can handle it accordingly.
In this case, you don't want to catch the exception. You're throwing it to alert the caller that they've made a mistake in the way they called your method. Catching it yourself would prevent that from happening. So yes, your code looks fine.
That's perfectly fine. You're throwing the exception, not catching/handling it, so you wouldn't need a try/catch block for it.
This is perfectly valid, you can use the same construct even with the constructors.
But What you should not do is
public int Method(int a, int b)
{
try
{
if (a < b)
throw new ArgumentException("the first argument cannot be less than the second");
}
catch (Exception)
{
}
return 0;
}
You've got the right idea. You could use your code like this:
void MyMainMethod()
{
// ... oh, let's call my Method with some arguments
// I'm not sure if it'll work, so best to wrap it in a try catch
try
{
Method(-100, 500);
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
}
public int Method(int a, int b)
{
if (a < b) throw new ArgumentException("the first argument cannot be less than the second");
//do stuff ... and return
}
It might help to look through MSDN's Handling and Throwing Exceptions and Best Practices for Handling Exceptions
What you've done here is perfectly Ok.
A common pattern for arg checks is to wrap the check/throw code in a static "Contract" class ensuring you have a consistent approach to exception management when validating input arguments.
Slightly off topic but if using .NET 4.0 you can also look at the new Code Contracts feature for validation of method input and output.
All above answers are correct but I like to mention one additional point here which I did not see mentioned in any of the answers. The reason why you should throw an exception and not return an integer e.g. 0 or -1 for signalling that an error occurred, is that the returned integer can be mistakenly treated/assumed as a valid result of your method. It is an integer anyway, and your method, after performing its internal logic returns an integer. So the caller of this method can mistakenly treat any returned integer as a valid result, which can lead to bugs down the line. In that case, throwing an exception makes perfect sense.

Categories