Is it possible to continue running code from the point of failure? - c#

Okay, I have some very simple code which I will post below. Essentially, I have a connection to a database and I want to map a subset of columns in a query to a particular class. The problem is that it is possible for these to be null.
I would like to know if it is possible if an exception is thrown at a particular line, can we resume the entire block from the next line.
So if this code below was to execute and Line 6 catches an error. Is there an elegant way to catch the exception and make the code resume running at line 7. Essentially making it as though line 6 was never executed.
private static Column MapTableToColumn(OracleDataReader reader){
Column c = new Column();
c.ColumnName = Convert.ToString(reader["COLUMN_NAME"]);
c.DataType = Convert.ToString(reader["DATA_TYPE"]);
c.DataLength = Convert.ToInt32(reader["DATA_LENGTH"]);
c.DataPrecision = Convert.ToInt32(reader["Data_Precision"]);//<---Line 6
c.DataScale = Convert.ToInt32(reader["Data_scale"]);//<--- Line 7
c.AllowDBNull = Convert.ToBoolean(reader["ALLOW_DB_NULL"]);
c.IsReadOnly = Convert.ToBoolean(reader["IS_READ_ONLY"]);
c.IsLong = Convert.ToBoolean(reader["IS_LONG"]);
c.IsKey = Convert.ToBoolean(reader["IS_KEY"]);
c.KeyType = Convert.ToString(reader["KEY_TYPE"]);
c.IsUnique = Convert.ToBoolean(reader["IS_UNIQUE"]);
c.Description = Convert.ToString(reader["DESCRIPTION"]);
return c;
}
It is important to note I am not asking for best practice, it is not something I intend to use in actual code (unless its absolutely genius). I simply want to know if this is possible and how one would go about doing this if it were.
My Research
Most of my research is proactive as opposed to reactive. I would attempt to know if it is possible for the given field to be null before it is read from. If it is, then I'd do a check to determine if the field is null and then set it to a default value. It essentially avoids the possibility of an error happening which I believe is a very good solution. I just wanted to attempt this as I know that when an exception is thrown, the most inner exception contains the line number at which it was thrown. Based on this if you put the exception inside of the class throwing the exception you should hypothetically be able to use reflection in order to continue running from its last point. I'm just not sure how you'd go about doing this. I've also considered the possibly of putting try catches around every single line which I think would be very effective; however, I think that it would be very ugly.

No, what you are asking for is not possible in C#.
Instead the proper solution to this problem is to use better parsing methods that won't throw exceptions in the first place. If your input values can be null, then use parsing methods that can accept null values.
The first thing you probably need to do is use nullable types for your int/bool fields, so that you can support null values. Next, you'll need to create your own methods for parsing your ints/bools. If your input is null, return null, if not, use int.TryParse, bool.TryParse (or as for each if your input is the proper type, just cast to object).
Then by using those methods, instead of Convert, you won't be throwing exceptions in the first place (which you shouldn't be doing here even if it could work, because exceptions are for exceptional cases, not expected control flow).

If the exception is expected then it is not exceptional. Never never never catch a null reference exception. A null reference exception is a bug. Instead, write code to avoid the bug.
You can easily write helper methods that test for null, or use methods like Int32.TryParse that can handle malformed strings.

Check for IsDBNull
SqlDataReader.IsDBNull Method
And Reader has methods for each SQL datatype
For example
SqlDataReader.GetSqlBoolean
If the data is in SQL as string (char,nchar) then first check for null and then TryParse
For example
DateTime.TryParse
And ordinal position is faster
This is a sample for a nullable Int16
Int16? ID;
ID = rdr.IsDBNull(4) ? (Int16?)null : rdr.GetInt16(4);
If you want a default
Int16 ID;
ID = rdr.IsDBNull(4) ? 0 : rdr.GetInt16(4);

You'd need a try/catch around every single variable assignment, and you'd need to initialize all your Column instance values before you tried. This would be relatively slow.
As for reflection based on the line number: I wouldn't rely on the line number because one simple, innocent change to the code will throw it off completely.
I'd check for nulls specifically. If you expect them you can't hardly call them "exceptions". The method that does that is reader.IsDBNull. It takes the column index (not the column name) so you'll need to resolve the index using reader.GetOrdinal:
if (reader.IsDBNull(reader.GetOrdinal("Data_Precision"))) {
// It's null
} else {
// It's not null
}

Related

Safe usage of .FirstorDefault()?

When using Enumerable.FirstorDefault(), do I need to always catch the ArumentNullException that can be thrown when the collection operated on is null?
In the past I've always just done something like this:
WorkflowColorItemType associatedColor = ColorItems
.Where(ci => ci.AssociatedState == WorkflowStateStatus.NotStarted)
.FirstOrDefault();
if (associatedColor != null)
{
this.ColorItems.CurrentColor = associatedColor;
}
In the context of this code snippet, I would never expect ColorItems to be null but is it good practice to be enclosing every instance of snippets like this in try catch blocks so I can handle the off chance that the ColorItems collection might be null?
If you don't expect the collection to ever be empty, and it would be an error in your program for it to be empty, then don't use FirstOrDefault in the first place, use First. Since it's not an expected situation for you to be in you want to draw attention to the problem because it's a sign that something is wrong.
If it's entirely valid for the collection to be empty, and you want to use the first item only if there is at least one item, then using FirstOrDefault and providing a null check is fine.
Apply the same logic to the collection being null, and not empty. If it is expected that the collection be allowed to be null, then check for it using an if. If it's not expected that the collection be allowed to be null (which is generally the case for most uses of collections) then you shouldn't check, and you want the exception to be thrown as it will draw attention to the bug in the code that is supposed to populate that collection. Trying to catch the exception and move on is trying to obscure the bug which prevents you from finding and fixing it.
Yes, certainly. You need to be defensive all the time.
In fact, if associatedColor is null, that means there is something wrong, hence you need to handle it.
In fact, your code used to be wrapped in a try/catch block to handle exceptions, since, exceptions are "expensive", this is cheaper and nicer way to handle exceptional cases.
In any case, I would almost always use FirstOrDefault or something simirlar, like SingleOrDefault then I would do the null check.
The built in LINQ functions (like .Where() here) always return an empty enumerable if there are no results, not null. So there is no need to check for null after doing the .Where()
Depending on where ColorItems comes from, you should check for null on the object:
if (ColorItems != null)
{
}
else
{
}
There's no need to put a try/catch block around the code, but you should be checking for null just to be safe. In fact, using try/catch in a scenario like this, where you can just check for a null object, is a bad programming practice.

possible invalidoperationexception correct way to handle it

I'm confused as to the best way to try and deal with possible InvalidOperationException.
In my code, I get a blue line under (decimal)data.CurrencyExchangeRate so changing the code to:
data.CurrencyExchangeRate.GetValueOrDefault() removes the blue line.
As the data is from a database and the column is a decimal, it will never be null.
So is GetValueOrDefault the best way to deal with the possible error?
I'm just not sure how best to handle it.
Thanks
Assuming CurrencyExchangeRate is a nullable decimal, the GetValueOrDefault extension method is your safest bet - if you want to use a default of zero when the value is null.
For other default values, such as 1, use something like this:
decimal val = data.CurrencyExchangeRate.HasValue
? data.CurrencyExchangeRate.Value
: 1M;
The only exceptions you'll catch from GetValueOrDefault will be from the system such as OutOfMemoryExceptions etc. So it's unlikely you'll get an error here.
You should still use a try/catch. Never assume that the data from the database is always valid. For example, what if I changed the datatype in the database to be a VARCHAR and added a null value, your application would crash. Therefore it makes sense to handle the exception.
try {
var value = data.CurrencyExchangeRate.GetValueOrDefault();
} catch (InvalidOperationException e) {
// Log the exception
}

When to raise an exception or return null?

I have a few functions on Data access layer
public Order RetrieveById(int id)
public List<Order> RetrieveByStatus(OrderStatus status)
Now i am bit confuse on exception raising.
In case of RetrieveById function, id which is less than 1 is an invalid id therefore i feel like raising an exception. And i feel like returning null for the Id which doesn't exist in the database. Then it feels like i am over complicating.
In case of RetrieveByStatus, i feel like returning a empty list when there is no data in the database for that status.
However i have seen that some people raising an exception when RetrieveById cannot return anything but then RetrieveByStatus should not raise exception when there is no record or should it?
Could anyone please clarify these concepts for me?
In the first case i would possibly go for a exception and handle myself,instead of returning null.What if your first method is used in a way that the returned object is saved to a Order reference.There is a very high chance of NullReferenceException being thrown,when someone tries to call a method or property on that object.
For the second method i would go for a empty list as some have suggested.
I would prefer to return null in the first case and an empty list
in the second case.
But if you want to raise exception then You can raise exception for public Order RetrieveById(int id) because it means that id is not valid as calling the first method means that you know the id and the it needs to be there.
In the second case the OrderStatus might be valid and there is not record found against it so returning an empty list is a good idea.
Read MSDN first: Creating and Throwing Exceptions (C# Programming Guide). It lists both situations when you are expected to throw an exception, and when to avoid it.
Also take into account What is the real overhead of try/catch in C#?
In any case you'll have to process either null return or an exception thrown
As for myself, I'd prefer in both your methods not to throw exception explicitly. I'd say, there is nothing bad, if your method returns null, if it failed to find an object by id. Whereas the RetrieveByStatus method could return an empty collection, not null.
Besides you could follow the pattern used in LINQ, where you have, say, Enumerable.First and Enumerable.FirstOrDefault methods (either throwing an exception or returning null), so you could use the appropriate one in a certain situation, when the id is 100% valid or when on the contrary it could be missing. While methods returning a sequence of elements don't throw exceptions if the sequence to return appears to be empty; consider Enumerable.Where.
I like to avoid returning null whenever possible, because NullRefExceptions are much more cryptic than a specific exception, say OrderNotFoundException. Also, code gets pretty obtuse when you have to constantly expect entities to be null. This ought to be an exception case anyway -- where did you get that id if it doesn't exist in the db?
On the cases you suspect this is more likely to throw an error, you could add a DoesObjectExist or TryGet type method (or even extension method).

Handling exceptions in a property's set/get

In the example code below I am taking a list of strings and concatenating them to a delimited string. The problem occurs when I use the setter with an empty list. The ToString method throws an ArgumentOutOfRangeException since the second parameter is a -1.
How should conditions (exceptions thrown in getters/setters) like this be handled?
I don't like the fact that the setter throws an exception since the caller doesn't know about the internals of the class and therefor should not have to handle (or even know how) the exception. Catching all exceptions in the getter/setter and quietly handling them also sounds like a bad idea since the caller will not know the getter/setter failed.
//I realize that this isn't the best code but I wanted to produce an example
//to demonstrate my question.
private string theStringVariable;
const string DELIMITER = ",";
public IList<string> StringList
{
set
{
StringBuilder stringBuilder = new StringBuilder();
foreach(string entry in value)
{
stringBuilder.Append(entry);
stringBuilder.Append(DELIMITER);
}
theStringVariable = stringBuilder.ToString(0, stringBuilder.Length - 1);
}
}
You should check for the potential, common error conditions, and throw your own exception (prior to the StringBuilder errors) right up front, with a meaningful error message.
In your case, you'll most likely want to use some form of ArgumentException if the setter is called with an Empty string list. The key here is that your exception can say "the argument contained an empty collection" instead of "index out of bounds", which is going to make the caller understand, immediately, why they have a "real" problem in their call.
On a side note: In cases like the code you posted - I'd also consider making this a method instead of a property. You're doing quite a bit of "work" in this property setter, which is going to be somewhat unexpected. By making this a method, you'll be giving the user a clue that there's a bit of "processing" occurring within this property...
I don't think your issues deal with best practices.
The best practice you need to watch in your case is the line that says
stringBuilder.ToString(0, stringBuilder.Length - 1);
You are causing the exception to be thrown by not checking the string length. If your length is 0, just return empty string.
If we are talking in generalities, if you have the ability to code around common issues, empty sets, badly formatted data, then you should do your best to shield the user from unnecessary errors.
However* sometimes it is better to abruptly/loudly fail then it is to silently fail.
First of all, if you can spot someone that might cause an exception --- fix it so the exception doesn't happen. In this case, check for an empty list before the loop and set the varaible appropriately.
Otherwise, catch the exceptions (the one you expect might happen(*)), an throw a new more appropriate exception (with the original as the inner exception)
(*) Catch only the one's you expect might happen -- let the unexpected one bubble up to the user.
Code Complete suggests if you can handle the exception locally that you do so: "Don't use an exception to pass the buck". In the example given this would mean check for an empty value and handle this appropriately in the setter.

Whether to check for null

I know that you should always check incoming params to a method for null. But what if I have this scenario with a try/catch referring to a local variable. Do I really need to check for null below? Because it's gonna catch it anyway if it's null and the next line of code tries to use the refundResponse variable:
public string DoRefund(...)
{
try
{
......
string refundTransactionID = string.Empty;
......
RefundTransactionResponseType refundResponse = transaction.DoRefund(...);
if (refundResponse != null)
refundTransactionID = refundResponse.RefundTransactionID;
.....
}
catch (Exception ex)
{
LogError(ex);
return ex.ToString();
}
}
Remember I'm talking specifically about local variables and checking those inside a method, not incoming params to a method.
All I'm asking here is do I need to check for null before setting refundTransactionID or do I just set it without the if assuming that the compiler will handle and throw if it is null which will be caught and thrown back as a string to the caller in this case.
or should it be
if (refundResponse == null)
return null;
or just take the check out completely for this local variable assignment and then since in this case I have a try/catch I'm handling any exceptions picked up by the compiler naturally by returning the exception as a string to the caller (it was not my decision to send back a string, it was a requirement by my boss...so bypass that debate for now):
refundTransactionID = refundResponse.RefundTransactionID;
ultimately the rest of the code further down the line in the method is dependent on a valid refundTransactionID.
Exceptions are for exceptional conditions. If you can check for a continuable error, do so, please!
I know that you should always check
incoming params to a method for null.
No, not necessarily. What you should specify is the contract of your method. It's perfectly acceptable (and common) to specify that you'll throw a NullPointer/NullReferenceException for a null parameter. Then you don't need any checking.
You can also check for null, but this only makes sense if you can actually handle a null usefully (e.g. substitute a default value).
You should have to check for null in that instance. Your application logic should be able to handle these kind of situations, without the need for exceptions.
An alternative to testing is the Null Object pattern. Instead of returning Null, or a valid transaction, the transaction::DoRefund() method returns a null object: an object that offers the same interface as the RefundTransactionResponseType instances, but its methods do nothing. With this there is no need to test whether for Null.
The should be used wisely as this can easily hide problems.
No you don't need to check for null, there. That opens up another question, though, do you really need to check for null in incoming parameters?
Remember: that's a behavior. You have to test that behavior.
But if you can't continue at that point let the exception propogate.
No, doesn't look like you should check for null here. And I also wouldn't check for null for ALL incoming parameters (as your description suggests).
It's also odd that you're returning a transactionID as a string OR the message of an exception. How will the caller of this method know if an exception happened?
If you really want to log the exception, how about something like this:
public string DoRefund(...)
{
try
{
return transaction.DoRefund(...).RefundTransactionID;
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
You should check for null rather than letting the exception handling handle it. As leppie said, exceptions are for exceptional conditions not normal flow of control. If you know what issues can occur then you should gracefully handle them.
Another thing to keep in mind is the performance impact of exceptions. When the exception is thrown the JVM has to unwind the call stack. In your example the exception is then also logged. All of this takes time and is much slower than a simple "if" check.
I'd suggest checking for the null then doing some kind of soft error handling instead of just letting it catch and throwing an error message.
It depends on what it means to your program when (refundResponse == null). If this has some meaning, then it makes sense to report a more informative error. If it should never happen and would indicate a flaw in the DoRefund method, then I think it's fine to allow the null to cause an exception later. In the latter case, I'd only have a specific check if you're suspicious of the method and whether it's behaving as it's supposed to.

Categories

Resources