Catch block never firing inside a LINQ statement - c#

I have some data I am deserializing inside a Linq statement:
var scheduledData = results
.Where(o => o.Result.IsValid)
.SelectMany(o => JsonConvert.DeserializeObject<List<CalendarJob>>(o.Result.Response))
.ToList();
This is throwing an error. I never see this error in the debugger. The returned web page lists a 500 error showing this. So I added some handing:
var scheduledData = results
.Where(o => o.Result.IsValid)
.SelectMany(o => {
try {
return JsonConvert.DeserializeObject<List<CalendarJob>>(o.Result.Response);
}
catch {
return new List<CalendarJob>();
}
})
.ToList();
Yes this is really ugly. I only did this so I could put a breakpoint on the catch block so I could inspect some values. This is not code I would leave in place! :)
I put a breakpoint on the return statement inside the try block and also the catch block. Then I execute the code. The try statement hits and execution is gone. The catch block never fires nor does any other code in my method.
Should this catch block be allowed in linq? I sure thought so?
Yes, I am in debug mode. Yes, I have cleaned and rebuilt. The breakpoint on my try block does indeed hit. I can inspect the value of the string about to be deserialized and the value is not right. It's "". I do not mean string.Empty, I specifically mean the string contains two bytes and both are the double quote character. The service I am getting the data from is not returning good data. But my catch block never fires.
One more thing to note. I put the entire thing into a try...catch block and that catch block does hit. Only the one inside LINQ does not.

Yes - this will work the way you think it will.
The only time it won't work will be an exception you cannot catch, like a StackOverflowException.
To prove it, just execute the folllowing code in Visual Studio, or Linqpad and observe the breakpoint is hit twice.
var list = new List<string>
{
"a",
"b"
};
list.Select(i =>
{
try
{
return int.Parse(i);
}
catch
{
return 0; // Put a breakpoint here.
}
}).ToList();

I found the cause. Internally JsonConvert doesn't throw an error with invalid Json. Instead it returns null. So my try...catch block around the JsonConvert didn't do anything because there was nothing to catch. Next, SelectMany was expecting a List<> item back and tried to enumerate it to select the elements out of it. Because it received null, the error was thrown here and not inside the Json conversion. This is why the outer try...catch picks up the error but the one in the OP above does not.
I accepted RB's answer because he answers my original question. This is simply an explanation for any future finders.

Related

Why doesn't the catch statement catch all the exceptions? [duplicate]

This question already has answers here:
How to handle exception raised in linq
(2 answers)
Closed 6 years ago.
I'm testing the method below and I realized that when I enter wrong file name, the error gets caught but when I don't have an element on the position specified, the error of IndexOutOfBounds crashes the program. The latter goes also for converting errors.
private static IEnumerable<Thing> Initialize()
{
try
{
string[] things = System.IO.File.ReadAllLines("things.txt");
return things.Select(_ => new Thing
{
Name = _.Split(';')[0],
Id = Convert.ToInt32(_.Split(';')[0])
});
}
catch(Exception exception)
{
Console.WriteLine(exception.Message);
return new List<Thing>();
}
}
Why doesn't some errors get handled despite the most general Exception type in the catch? Does it have to do with LINQ expression failing? If so, how do I force the catching, then?
This is because you return IEnumerable.
The lambda inside Select doesn't execute immediately, but only on accessing the enumerable (iterating items).
If you add call "ToArray" after "Select" then all items will be calculated and IndexOutRangeException will be catched in your catch block.
return things.Select(_ => new Thing
{
Name = _.Split(';')[0],
Id = Convert.ToInt32(_.Split(';')[0])
}).ToArray();
You are returning an IEnumerable<> which implies deferred execution.
So anything inside the lambda is actually executing later, outside the try/catch.
If you want to catch all errors, include a .ToList() , like
return things.Select(...).ToList();
I have experienced this a couple of years ago, and the explanation I found online is that it is because of unmanaged assemblies and code. Something that is out of the application domain. Mostly when you have a lower level (os level) operation

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

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.

Do I need to initialize a variable, even if I know it will be assigned before used?

In an ASP.NET MVC app, I have code that boils down to the following:
public ActionResult Test() {
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
}
... do additional validation ...
if (ModelState.IsValid) {
return RedirectToAction("Success?" + query);
}
return View(); // Show validation messages
}
The above code has a compile error ... query might not be initialized.
However, the logic in the code will clearly initialize query before using it.
What is the best way to resolve this issue?
The C# compiler is looking at your code and seeing that the value of the variable is initialized in a try block and is then used later on. It can see that a logical branch of execution exists where an exception is thrown, is caught, and then the subsequent code is executed with an uninitialized value.
The simplest way to stifle the error is to assign a default value to the field. null is sufficient. As you're adding the error to the MVC model state and are checking that value later on before accessing query, you shouldn't be in a situation when the default value will matter.
You are wrong, What if GenerateQueryString throws an exception? What will be the value of Query?
You might want to do a query = "Error"; or something in your catch block. This because appareantly you want the application to run if an exception in GenerateQueryString is thrown.
EDIT
I would recommend against presetting query with a default value. This because the meaning is different. A default value is different than a certain value at a certain moment. Doing so will also prevent the compiler from warning you when you create a new code path but forget to setup a value for query
If there is exception in the call to GenerateQueryString the value of query will be undefined.
Try
string query = string.Empty;
to have a definite assignment to the variable.
Alternatively, if an exception should abort the execution, this will work too:
string query;
try {
query = GenerateQueryString();
}
catch (Exception ex) {
ModelState.AddModelError("error", ex.Message);
return View();
}
The Code is NOT clearly initialized. When the GenerateQueryString() Method throws an Exception, no value will be set. You should set the String to null and check for null before you use it, als you don't break in the catch-block.
Just because YOU know that it will be initialized (it may not be by the way in your code), the COMPILER can't know that - it's called the Halting problem.
So the compiler errs on the side of caution, something .net does a lot (e.g., no fallthrough in switch..case).
The thing here is that local variables must be initialized before read - they won't be initialized by default and this prevents from bugs programmers often makes. Some time ago I was looking for the answer to this simple situation:
bool a = true, b;
if (a == true) //here everything is OK, because a is initialized
b = true;
if(b == false) //here you get an error, I thought b == false by default
return;
I found on stackoverflow deep explanations, why it works so(couldn't find at the moment which I was reading). But you can read Absence of evidence is not evidence of absence interesting article. Maybe it will explain what I tried to say :)
Resume:
In your case you need to initialize query or set variable in catch block
Just change the declaration of query in: string query = string.Empty;.
The problem is that query is initialised in the try block, but query is declared in the block above. You must initialise it at the top level block.
It could just be that your GenerateQueryString() throws an exception. Personally, I prefer to initialize my variables, just to be on the safe side. For this reason you might just initialize to query to:
string query = String.Empty;
It doesn't hurt to be on the safe side.

C# - How to use unassigned variable in try catch block

crmFactory.RegisterDemoAccount throws Exception. In order to use the variable res I need to initialize it.
Since AccountRegistrationResponse is not initializable, how can I declare res without getting compilation errors about using unassigned variables?
I can assign it to null, but I don't think this is a good programming approach.
AccountRegistrationResponse res /*=null*/;
try
{
res = crmFactory.RegisterDemoAccount(CrmConfigRepository.CrmOwnerUserId
, CrmConfigRepository.CrmOrganizationName
, CrmConfigRepository.CrmBusinessUnitName
, demo.getData());
}
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
}
_log.Debug(res.getString());
You shouldn't try to continue your method after catching an unknown exception. Anything could have gone wrong and it makes no sense to assume that it's safe to continue. Only bad things can happen if you try.
Either return an error result, or better, just rethrow the original exception:
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
throw;
}
Now the compiler can see that res will always be assigned after the try block completes successfully.
I understand your reluctance to assign res to null - it feels pointless, and therefore wrong. It is a common approach in situations like this, though, when an object is needed outside the block in which it's assigned. Assuming you're doing the right thing in assigning your variable in a try/catch block (and it's not an uncommon pattern, in many cases), I wouldn't worry about it.
However, what would happen if the assignment failed? The second logging call would try to dereference res, and throw a NullReferenceException. That's not good.
You need to put the logging line inside the try/catch so that the compiler knows that res has been initialised.
try
{
res = ...
_log.Debug(res.getString()); }
catch (Exception e)
{
_log.Error("Cannot create demo account", e);
}
It's THE right approach. Only thing, if null is a valid return value of RegisterDemoAccount, you could add a bool initialized = false that you set to true just after the RegisterDemoAccount.
Assign it to null, like you said, if you need it outside of try/catch. It's not bad way of programming.
but I don't think this is a good programming approach.
Why? If you don't initialise res and then RegisterDemoAccount(...) (or another expression before it) throws then res will not be assigned in the try statement.
Therefore execution could reach the final statement (after the catch block) with res unassigned.
The problem is the use of res in that last statement – the compiler can see it can get to this point without initialisation.

Categories

Resources