rewriting recursive form to iterative. exception handling - c#

Consider such a function:
void RequestThings(List<Things> container, Connection connection, Int32 lastVersion) {
var version = lastVersion;
try {
foreach(var thing in connection.RequestThings(version)) {
container.Add(thing);
version = thing.lastVersion;
}
}
catch(Exception ex) {
RequestThings(container, connection, version + 1);
}
}
But this choice is far not perfect: it involves adding to a recursion depth (up to a stack overflow) in case if there are (many) exceptions.
How do I rewrite this the iterative way?
I've tried to do this like:
var container = new List<Things>();
var version = getLastVersionFromDB();
foreach(var thing in connection.RequestThings(version)) {
try {
container.Add(thing);
}
catch(Exception ex) {
continue;
}
}
But it appears that exception doesn't get handled. How do I do this?
edit. the details
Connection.RequestThings(Int32 startVersion) requests data from a remote server. Accepts a seed version as its only parameter. There might be blocked/damaged documents which you cannot request though they appear on the results returned by calls to Connection.RequestThings(Int32 startVersion). This piece throws the exception
Don't know why but the inner try/catch in my iterative example doesn't catch the exception.

Generally, it's a bad idea to have a catch clause for all exceptions. Consider catching only a specific exception type to be sure that you're not swallowing unexpected errors.
Additionally, if you got a stack overflow in the first place, it indicates that you might be doing something wrong. For example, what happens if you pass an invalid version number to this method, and there are no documents with a larger version number available? This method will keep running forever, with no chance to gracefully cancel it. Especially since it seems that you are getting the "last version" from a database somehow; if this fails, you can be pretty certain that no higher version exists.
Having said that, you can simplify the method by creating an "infinite" loop and then using return to exit the method on success:
void RequestThings(List<Things> container, Connection conn, int version)
{
while (true)
{
try
{
foreach (var thing in connection.RequestThings(version))
{
container.Add(thing);
version = thing.lastVersion;
}
return;
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}
A slightly better approach might be to make sure that you really get the entire list on success, or nothing. The way your code is written right now leaves the possibility of container being filled multiple times if an exception happens while iterating.
List<Things> RequestThings(Connection conn, int version)
{
while (true)
{
try
{
// this will either create an entire list,
// or fail completely
return connection.RequestThings(version).ToList();
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}

Related

C# not entering exception after using throw

I'm a beginner programmer and I have been faced with exceptions recently. I've done this small test below and the output I received was not the same as the one I expected.
static void Main(string[] args)
{
ushort var = 65535;
try
{
checked { var++; }
}
catch (OverflowException)
{
Console.WriteLine("Hello!");
throw;
}
catch
{
Console.WriteLine("Here I am!");
}
}
I was expecting the program to do the following:
Try to var++, fail and create an OverflowException;
Enter Catch (OverflowException) and write "Hello!";
Throw an Exception and enter catch;
Write "Here I am!".
However, I only got on screen "Hello!".
EDIT: Thanks to those who commented. I think I'm starting to understand. However, my confusion originated because of this book I'm reading: C# 4.0.
I could show the text, however it is in Portuguese. I'm going to translate what it says: "Sometimes it is useful to propagate the exception through more than one catch. For example, let's suposse it is necessary to show a specific error message due to the fact that the "idade" is invalid, but we still need to close the program, being that part in the global catch. In that case, it is necessary to propagate the exception after the execution of the first catch block. To do that, you only need to do a simple throw with no arguments."
Example from the book
In this example of the book you can see the programmer do the same thing I did. At least it looks like it. Am I missing something? Or is the book wrong?
Hope you can help me. Thanks!
In short, you are doing it wrong. Let's visit the documentation
Exception Handling (C# Programming Guide)
Multiple catch blocks with different exception filters can be chained
together. The catch blocks are evaluated from top to bottom in your
code, but only one catch block is executed for each exception that
is thrown.
Although it doesn't specifically say you can't catch an exception that has been re-thrown in an exception filter, the fact is you can't. It would be a nightmare and have complicated and unexpected results.
That's all to say, you will need another layer (inner or outer) of try catch to catch the exception that is thrown in catch (OverflowException)
You'll get the output you expected if you nest try/catch blocks:
static void Main(string[] args)
{
try
{
ushort var = 65535;
try
{
checked { var++; }
}
catch (OverflowException)
{
Console.WriteLine("Hello!");
throw;
}
}
catch
{
Console.WriteLine("Here I am!");
}
}
I have two articles on exception handling I link often. I personally consider them required reading when dealing with them:
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
As for this case, you are not throwing a exception. You are re-throwing one you caught. Think of it like a fisherman doing "catch and release". It can be used for some scenarios, like this time I wrote a TryParse replacement for someone stuck on .NET 1.1:
//Parse throws ArgumentNull, Format and Overflow Exceptions.
//And they only have Exception as base class in common, but identical handling code (output = 0 and return false).
bool TryParse(string input, out int output){
try{
output = int.Parse(input);
}
catch (Exception ex){
if(ex is ArgumentNullException ||
ex is FormatException ||
ex is OverflowException){
//these are the exceptions I am looking for. I will do my thing.
output = 0;
return false;
}
else{
//Not the exceptions I expect. Best to just let them go on their way.
throw;
}
}
//I am pretty sure the Exception replaces the return value in exception case.
//So this one will only be returned without any Exceptions, expected or unexpected
return true;
}
But as a rule of thumb, you should be using stuff like "finally" blocks for cleanup work rather then catch and release. throw inside a catch block is something you use rarely.

Handling an exception on items in a for-each loop

I couldn't think of a good way to test it myself so asking this question:
Lets say I have a list of transactions that I have sending them one by one to a web service and the result of webservice call may be Success, Failed or something weird may have happened and it just crashes.
So the overall code I have is like this:
for each (transaction)
{
try
{
string result = webservice.Call(transaction);
if result == "Faild"
{
// log some errors.
}
}
catch (Exception ex)
{
// Log some errors, stack trace, etc...
}
}
So my question is: if it falls into an exception for one of the transaction calls, then does the whole thing stop? OR it will get out of the exception block and will move on to next item in the for-each?
A catch is a catch and will do what a catch is supposed to do.
The loop will not break unless you rethrow the exception.
If you want to complete the entire loop before telling the user that something went wrong you can do
something like this:
List<Exception> exceptions = new List<Exception>();
foreach (var transaction in transactions)
{
try
{
string result = webservice.Call(transaction);
if result == "Faild"
{
// log some errors.
}
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
if (exceptions.Any())
throw new AggregateException(exceptions);
It WILL continue looping until you have no more transactions to loop through. That's what is so useful about try catch.
Since the try/catch is inside the loop, it will run for each transaction call.
If you had put the loop inside the try, then it would blow up at the first exception.
Check out the information here on using try { ... } catch() { ... } finally { ... }, where you can have code that executes after the exception is handled.

function that recalls itself upon a catch of non-critical error

I got a function named inner_logic() that can throw many types of exception , each of one of two types: critical and non-critical. The logic of inner_logic() includes an "infinite" loop, so in case of a non-critical exception I'd wish to step back in to it. At that point you can ask why not catching the non-critical exception within the loop, and the reason is that it's an abstract class with a few inheritors, each have a unique loop. for clarification, what I want to do is something like:
public void logic()
{
try
{
inner_logic();
}
catch (non_critical e)
{
// log
logic();
}
catch(critical e)
{
// log
return;
}
public virtual void inner_logic(){}
As far as I can tell, I seems that it should work, and that all calls are "catchable", but it feels kinda hackish.
My Question is: Is there a better way for doing that, or a reason I should reconsider my suggestion?
I did something similar in the past. I try to avoid recursion so I did a loop instead.
public void logic()
{
bool running = true;
while(running)
{
running = false;
try
{
inner_logic();
}
catch(non_critical e)
{
running = true;
}
}
}
Actually, I did it a bit diffrently. Instead of a boolean, I counted the number of non_critical errors. If the number exceded 3 then I handled it as a critical error.
You should not do it this way, as if the current state of the application means that the non- critical exception is thrown repeatedly, a stack overflow exception will occur.
Catch the exception outside the method and repeat if needed.
It feels to me like it should just be looping:
while (true) // Or probably have a maximum number of retries
{
try
{
// Logic
// Break out of the loop by returning if we succeed
return;
}
catch (NonCriticalException e)
{
// Log, then let the loop continue
}
catch (CriticalException e)
{
// Log, then rethrow (in preference to returning)
}
}
With your original approach, if the non-critical exception just keeps happening, you'll get a StackOverflowException. I would definitely suggest adding a maximum retry count though. (Keeping track of the number of retries is good for logging, too.)

C# using an exception for flow control

I have some text in a string which I'm reading in. The object which contains the string provides a method for me to extract the contents of the string and then throws an exception (EndOfStreamException) when the string is empty. At that point I'd like to finish my data extraction and continue with working on it. I'm not very certain how to do this. Here is what I am guessing.
while(/*some condition on the data*/)
try
{
objWithString.ExtractData();
}
catch (Exception e)
{
if(e is EndOfStreamException)
{
break;
}
else
throw e;
}
}
That will work, but it would be better to catch the specific exception than to do the test at runtime, ie.
while (/*some condition on the data*/)
try
{
objWithString.ExtractData();
}
catch (EndOfStreamException)
{
break;
}
I'm not entirely sure if "break" will work inside a catch clause. If not, you may have to extract this into a method and use "return".
Generally using exceptions for flow control is considered poor design, since exceptions are intended for "exceptional" conditions and reaching the end of the stream is normal and expected, not exceptional. Of course, if you have no control over the implementation of the stream then you have to go with this approach.

C#: Equivalent of the python try/catch/else block

In Python, there is this useful exception handling code:
try:
# Code that could raise an exception
except Exception:
# Exception handling
else:
# Code to execute if the try block DID NOT fail
I think it's useful to be able to separate the code that could raise and exception from your normal code. In Python, this was possible as shown above, however I can't find anything like it in C#.
Assuming the feature or one like it doesn't exist, is it standard practice to put normal code in the try block or after the catch block?
The reason I ask is because I have the following code:
if (!IsReadOnly)
{
T newobj;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
}
Which requires the normal code to be in the try block because otherwise if an exception was raised and subsequently handled, newobj would be unassigned, but it feels quite unnatural to have this much code in the try block which is unrelated to the DataPortalException. What to do?
Thanks
I would prefer to see the rest of the code outside the try/catch so it is clear where the exception you are trying to catch is coming from and that you don't accidentally catch an exception that you weren't trying to catch.
I think the closest equivalent to the Python try/catch/else is to use a local boolean variable to remember whether or not an exception was thrown.
bool success;
try
{
foo();
success = true;
}
catch (MyException)
{
recover();
success = false;
}
if (success)
{
bar();
}
But if you are doing this, I'd ask why you don't either fully recover from the exception so that you can continue as if there had been success, or else fully abort by returning an error code or even just letting the exception propagate to the caller.
Barbaric solution: create an Else class derived from Exception, throw an instance of it at the end of the try block, and use catch (Else) {...} to handle the other stuff.
I feel so dirty.
This will might get downvoted but doesn't c# have goto(note I have almost no c# knowledge so I have no idea if this works).
what about something like
try
{
...
}
catch(Exception ex)
{
...
goto Jump_past_tryelse
}
...//Code to execute if the try block DID NOT fail
Jump_past_tryelse:
...
C# does not have such a concept, so you are just left with three options,
put the else code inside the try.
put the else code outside the try catch block, use a local variable to indicate success or failure, and an if block around your else code.
put the else code in the finally block, use a local variable to indicate success or failure, and an if block arount you else code.
Allow me to repeat an idea from a similar StackOverflow question. You cannot do this directly, but you can write a method that encapsulates the behavior you need. Look at the original question to see how to implement the method (if you're not familiar with lambda expressions and Func delegates). The usage could look like this:
TryExceptRaise(() => {
// code that can throw exception
}, (Exception e) => {
// code to run in case of an exception
return (...);
}, () => {
// code to run if there is no exception
return (...);
});
Just put your "else" block before the catch. Then, it will only execute if code execution reaches that point:
try
{
fee();
fi();
foe();
fum();
/// put your "else" stuff here.
/// It will only be executed if fee-fi-foe-fum did not fail.
}
catch(Exception e)
{
// handle exception
}
Given that, I fail to see the use of try..catch...else unless there's something vital missing from the OP's description.
With C# version 7, you could use local functions to emulate this behaviour:
Example 1: (since C# version 7)
void Main()
{
void checkedCode()
{
try
{
foo();
}
catch (Exception ex)
{
recover();
return;
}
// ElseCode here
}
checkedCode();
}
If you prefer lambda syntax, you could also declare a run method
void Run(Action r) { r(); }
which only needs to be there once in your code, and then use the pattern for anonymous methods as follows
Example 2: (older C# versions and C# version 7)
Run(() => {
try
{
foo();
}
catch (Exception)
{
recover();
return;
}
// ElseCode here
});
whereever you need to enclose code in a safe context.
Try it in DotNetFiddle
Notes:
In both examples a function context is created so that we can use return; to exit on error.
You can find a similar pattern like the one used in Example 2 in JavaScript: Self-invoking anonymous functions (e.g. JQuery uses them). Because in C# you cannot self-invoke, the helper method Run is used.
Since Run does not have to be a local function, Example 2 works with older C# versions as well
You could do something like this:
if (!IsReadOnly)
{
T newobj = null;
try
{
newobj = DataPortal.Update<T>(this);
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
}
if (newobj != null)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
that would be the empty statement like hits
try
{
somethingThatCanThrow();
}
catch(Exception ex)
{
LogException(ex);
return;
}
ContinueFlow();
if (!IsReadOnly)
{
T newobj;
bool Done;
try
{
newobj = DataPortal.Update<T>(this);
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
Done = true;
}
catch (DataPortalException)
{
// TODO: Implement DataPortal.Update<T>() recovery mechanism
Done = false;
}
finally
{
if (newobj != null && Done == false)
{
List<string> keys = new List<string>(BasicProperties.Keys);
foreach (string key in keys)
{
BasicProperties[key] = newobj.BasicProperties[key];
}
}
}
}

Categories