Null reference exception stops the code execution inside of try block - c#

So I have a code segment where I am expecting a method that is repeatedly called from inside a loop to return null at one point - null is returned because the table cell that this method tries to read from is empty. And that part is clear, that's not the problematic part of the behavior. Here is that part of code:
while (!String.IsNullOrEmpty(columnI_value))
{
typeOfShareLineCounter++;
try
{
columnI_value = sheet.GetRow(3 + typeOfShareLineCounter + typeOfShareStartIndexNewFile).GetCell(8).ToString();
}
catch
{
}
}
What I don't understand is why does program execution stop when an empty cell is reached in this case? I get NullReferenceException, but I am expecting the program to continue since the line of code where this exception occurs is inside the "try" block as you can see above.
Is it because of some Visual Studio setting?
As a side note, in a "normal" scenario, I could have probably just checked what the GetCell method returns and if it's null, just break out of the loop (because null in this case means that we have reached the end of the file segment that needs to be read).
However, GetCell here produces an exception in case the cell it is trying to read is empty. This is the reason I used the try-catch. But I was not expecting the program execution to halt in this case. At the moment, I do not see a way to handle the exception without it breaking the program. Btw, this problematic method (GetCell) is a part of the NPOI library for working with excel files.
Thanks a lot for your help.

Why don't you check if something is null before trying to access it?
I think GetCell throws an exception because GetRow returns null.
Also not clear what value is initially in columnI_value.
I would use something like this (just guessing what this code is expected to do):
typeOfShareLineCounter = 0;
while (true)
{
var cell = sheet.GetRow(3 + typeOfShareLineCounter + typeOfShareStartIndexNewFile)?.GetCell(8);
if (cell == null)
continue;
columnI_value = cell.ToString();
if (String.IsNullOrEmpty(columnI_value))
break;
typeOfShareLineCounter++;
}

Related

Do we get any benefit from adding null check if we are already using catch all Exception handler?

This is specific to .NET
I am writing a code piece where I have to use catch all exception handler. I call a series of function which may return null. I do not want to continue if any of them return null as I have an alternate but costly method to get the same result. I want to know if I should be using the series of null checks or not.
My code looks something like:
var some_info = null;
try{
var a = GetA();
if(a != null){
var b = a.GetB();
if(b != null){
var c = GetC(b);
if(c != null){
some_info = c.GetSomeInfo();
}
}
}
catch(Exception e){
// cant do anything here but I need above code to be silent
}
if(some_info == null)
some_info = GetSomeInfoFromHeavyMethod();
in C# if we try to use null reference it throws an exception so if any of the variables above will be null a NullReferenceException will be thrown. Therefore we can write the above code like
var some_info = null;
try{
var a = GetA();
var b = a.GetB();
var c = GetC(b);
some_info = c.GetSomeInfo();
}
catch(Exception e){
// cant do anything here but I need above code to be silent
}
if(some_info == null)
some_info = GetSomeInfoFromHeavyMethod();
My question is, should I use null checks here or let exception handler work here? My gut feeling says I should use the null check as it is good practice but, I have a doubt as I have to use catch all exception handler here and I already have to bear cost of try/catch block.
Yes, I would strongly advise using null checks:
It shows that you expect that the values can be null, and that that in itself is not a problem
If you ever add logging in your catch block, you can easily do so without being spammed by easily-avoidable messages
When debugging the code, you really don't want to end up with the debugger stopping for a NullReferenceException due to just not doing checks
You say that you "already have to bear cost of try/catch block" - it's not clear whether you're talking about the code readability cost or performance cost, but there's basically no performance cost for a try/catch block if no exception is thrown. Compare that with the case when an exception is thrown, which definitely has performance implications.
Ultimately, I'd consider every NullReferenceException to be a bug somewhere - it's the kind of exception that should always cause you to either add more validation (e.g. to throw ArgumentNullException) or handle the value being null. That wouldn't the case in your code.
With some refactoring you may be able to use the null-conditional operator introduced in C# 6 to reduce the code though. You might end up with:
someInfo = GetA()?.GetB()?.GetC()?.GetSomeInfo();
Exceptions are supposed to be thrown when exceptional situations occur. So, it all depends on whether you want to consider the case of a function returning null exceptional or not. There is no hard rule.
Though I would suspect that if the functions are returning null instead of throwing an exception, then a certain choice has already been made, by those who implemented those functions, that the situation is not exceptional. But of course at the place where you call these functions you may want to redefine what is exceptional and what isn't.
There is, however, a little technical issue: throwing an exception is extremely know on Microsoft's implementation of C#, (possibly also on Mono? I don't know) so we unfortunately tend to favor not considering certain situations exceptional (and therefore not throwing an exception) when the choice is borderline and performance is an issue.

C# What happens to code in try statements that didn't throw an exception after one is thrown

So, if I had something like this:
try
{
variable = Image.FromFile("Image1");
variable2 = Image.FromFile("Image2");
variable3 = Image.FromFile("Image3");
}
catch (Exception e) { }
What would happen if the second line threw an exception? Would variable 1 be assigned correctly and not 2 or 3? Or would it attempt to do 3 after handling the exception?
Since all variables are local (scoped) to the try block, it really does not matter because you can not access any of the variables outside of the block.
When an Exception is encountered control is transferred to the inner-most catch, there is no way to ignore it and continue at the next statement.
Update
With your changes, if the 2nd FromFile throws, then variable will have an Image. variable2/3 will see no change (so most likely will null).
It falls out after the 2nd statement if that one throws. The first statement would succeed. The 3rd would never be evaluated.
Like the other poster said, it doesn't matter in this case since the variables are local and the ReadFromFile doesn't have side effects.
The first variable named variable would successfully have a value assigned to it.
The exception is thrown on line two and anything after that is discarded but anything prior will execute. So to simplify this further:
1st statement executes .
2nd throws exception value is not stored in variable.
3,4,5... won't execute.
If you had a try/catch/finally then the finally will always execute.
If you want more in-depth breakdown of how exception handling works take a look at this article.
http://www.codeproject.com/Articles/125470/Exception-Handling-for-C-Beginners

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

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
}

Why do I get "Sequence contains no elements"?

NOTE: see edits at bottom. I am an idiot.
I had the following code to process set of tag names and identify/process new ones:
IEnumberable<string> tagNames = GetTagNames();
List<Tag> allTags = GetAllTags();
var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name == n));
foreach (var tagName in newTagNames)
{
// ...
}
...and this worked fine, except that it failed to deal with cases where there's a tag called "Foo" and the list contains "foo". In other words, it wasn't doing a case-insensitive comparison.
I changed the test to use a case-insensitive comparison, as follows:
var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)));
... and suddenly I get an exception thrown when the foreach runs (and calls MoveNext on) newTagNames. The exception says:
Sequence has no elements
I'm confused by this. Why would foreach insist on the sequence being non-empty? I'd expect to see that error if I was calling First(), but not when using foreach?
EDIT: more info.
This is getting weirder by the minute. Because my code is in an async method, and I'm superstitious, I decided that there was too much "distance" between the point at which the exception is raised, and the point at which it's caught and reported. So, I put a try/catch around the offending code, in the hope of verifying that the exception being thrown really was what I thought it was.
So now I can step through in the debugger to the foreach line, I can verify that the sequence is empty, and I can step right up to the bit where the debugger highlights the word "in". One more step, and I'm in my exception handler.
But, not the exception handler I just added, no! It lands in my outermost exception handler, without visiting my recently-added one! It doesn't match catch (Exception ex) and nor does it match a plain catch. (I did also put in a finally, and verified that it does visit that on the way out).
I've always taken it on faith that an Exception handler such as those would catch any exception. I'm scared now. I need an adult.
EDIT 2:
OK, so um, false alarm... The exception was not being caught by my local try/catch simply because it was not being raised by the code I thought. As I said above, I watched the execution in the debugger jump from the "in" of the foreach straight to the outer exception handler, hence my (wrong) assumption that that was where the error lay. However, with the empty enumeration, that was simply the last statement executed within the function, and for some reason the debugger did not show me the step out of the function or the execution of the next statement at the point of call - which was in fact the one causing the error.
Apologies to all those who responded, and if you would like to create an answer saying that I am an idoit, I will gladly accept it. That is, if I ever show my face on SO again...
It's not as proper or clean, but how does this work:
var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.ToUpper() == n.ToUpper()));
Exception handling is fun on deferred actions. The Enumerable.Where method (and most linq methods) are not executed until the query is enumerated.
IEnumerable<int> query = Enumerable.Empty<int>();
int myNum = 0;
try
{
query = Enumerable.Range(1, 100).Where(i => (i/myNum) > 1);
}
catch
{
Console.WriteLine("I caught divide by zero"); //does not run
}
foreach(int i in query) //divide by zero exception thrown
{
//..
}
In your particular case:
IEnumberable<string> tagNames = GetTagNames();
I bet GetTagNames has a Enumerable.First or Enumerable.Single inside there somewhere. If the result of GetTagNames is deferred, you must enumerate that result to get the exception to occur. That is why the commenters are recommending you call ToList on the result of GetTagNames - to enumerate it and get the exception to occur before your use of tagNames in a complicated query.

Handling a null exception C#

Ok, new coder here looking for a little insight into this problem. So I have a for loop like that starts like this:
for (int i = 0; i < rowHandles.Length; i++)
{
.........code....
}
rowHandles is an int array that contains rows of data. This for loop has code that deletes the rows of data when a delete button is clicked, to be specific it is a grid tool strip Delete button and this is inside the delete button click event handler. The problem is the delete button can be clicked when there are no rows left, so rowHandles.Length is equal to null. How would I prevent this from stopping the program? Is there something I could add inside the for loop, in the for loop declaration, or outside the for loop to correct this? Maybe a try catch? How would this be structured around this specific problem/loop?
Thanks for all your help - Newbie Coder
If the problem is that rowHandles can be null then just add an explicit check for that which prevents you from executing the for statement.
if ( rowHandles != null ) {
for ( int i = 0; i < rowHandles.Length; i++ ) {
...
}
}
Another option would be to disable the delete button altogether if there are no rows to be deleted. The operation is invalid so prevent it from the start.
An important principle here is never handle an exception that you could have prevented in the first place. You should never ever ever handle a null reference exception; a null reference exception indicates a bug in your program that should be fixed, not an expected occurrance that should be trapped and ignored. Either write code that ensures that the value is not null, or detect that it is null and do not dereference it.
The problem is the delete button can be clicked when there are no rows left, so rowHandles.Length is equal to null.
This is wrong. When there are 0 elements, Length is set to 0. What is null is probably rowHandles. You need to handle that condition before you get into your loop.
If there are no rows left, rowHandles.Length will be zero not null. If you're getting rid of rowHandles after the loop, then you can just do:
if (rowHandles != null)
{
for (int i = 0; i < rowHandles.Length; i++)
{
// Code
}
}
No need for exception handling. On the other hand if you're allowing rowHandles to be changed by something else while that loop is running, that's another story.
It's not rowHandles.Length which is null, it's rowHandles itself.
A common solution would be:
if (rowHandles != null)
//Your loop here
It looks like Length is not the thin that is null. Rather it is rowHandles that is null and you are getting the null exception when trying to access the Length property.
if(rowHandles != null)
{
//for loop
}
I would suggest you try as much as possible to stick to the Single Responsibility Principle, in that you let the code do what it is intended to do, and handle the errors elsewhere.
It makes sense to me that rowHandles is used elsewhere, so you should centralize the process of checking whether or not it is null.
If you still choose to handle it in the code body you're referencing, any of the suggested solutions will work.
Change to a foreach loop:
foreach (var rowHandle in rowHandles)
{
// use rowHandle instead of rowHandles[i]
}
This way, provided the entire rowHandles object is not null (a quick null check can verify this) you will iterate over all items, and if there are no items, you wont iterate at all.

Categories

Resources