Example of "using exceptions to control flow" [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
What would a piece of code which "uses exceptions to control flow" look like? I've tried to find a direct C# example, but cannot. Why is it bad?
Thanks

By definition, an exception is an occurrence which happens outside the normal flow of your software. A quick example off the top of my head is using a FileNotFoundException to see if a file exists or not.
try
{
File.Open(#"c:\some nonexistent file.not here");
}
catch(FileNotFoundException)
{
// do whatever logic is needed to create the file.
...
}
// proceed with the rest of your program.
In this case, you haven't used the File.Exists() method which achieves the same result but without the overhead of the exception.
Aside from the bad usage, there is overhead associated with an exception, populating the properties, creating the stack trace, etc.

It's roughly equivalent to a goto, except worse in terms of the word Exception, and with more overhead. You're telling the code to jump to the catch block:
bool worked;
try
{
foreach (Item someItem in SomeItems)
{
if (someItem.SomeTestFailed()) throw new TestFailedException();
}
worked = true;
}
catch(TestFailedException testFailedEx)
{
worked = false;
}
if (worked) // ... logic continues
As you can see, it's running some (made-up) tests; if they fail, an exception is thrown, and worked will be set to false.
Much easier to just update the bool worked directly, of course!
Hope that helps!

Bad
The below code catches an exception that could easily be avoided altogether. This makes the code more difficult to follow and typically incurs a performance cost as well.
int input1 = GetInput1();
int input2 = GetInput2();
try
{
int result = input1 / input2;
Output("{0} / {1} = {2}", input1, input2, result);
}
catch (OverflowException)
{
Output("There was an overflow exception. Make sure input2 is not zero.");
}
Better
This code checks for a condition that would throw an exception, and corrects the situation before the error occurs. This way there is no exception at all. The code is more readable, and the performance is very likely to be better.
int input1 = GetInput1();
int input2 = GetInput2();
while (input2 == 0)
{
Output("input2 must not be zero. Enter a new value.");
input2 = GetInput2();
}
int result = input1 / input2;
Output("{0} / {1} = {2}", input1, input2, result);

Here's a common one:
public bool TryParseEnum<T>(string value, out T result)
{
result = default(T);
try
{
result = (T)Enum.Parse(typeof(T), value, true);
return true;
}
catch
{
return false;
}
}

Probably the grossest violation I've ever seen:
// I haz an array...
public int ArrayCount(object[] array)
{
int count = 0;
try
{
while (true)
{
var temp = array[count];
count++;
}
}
catch (IndexOutOfRangeException)
{
return count;
}
}

I'm currently working with a 3rd party program that does this. They have a "cursor" interface (basically an IEnumerable alternative), where the only way to tell the program you're finished is to raise an exception. The code basically looks like:
// Just showing the relevant section
bool finished = false;
public bool IsFinished()
{
return finished;
}
// Using something like:
// int index = 0;
// int count = 42;
public void NextRecord()
{
if (finished)
return;
if (index >= count)
throw new APIProgramSpecificException("End of cursor", WEIRD_CONSTANT);
else
++index;
}
// Other methods to retrieve the current value
Needless to say, I hate the API - but its a good example of exceptions for flow control (and an insane way of working).

I'm not fond of C# but you can see some similarities between try-catch-finally statements and normal control flow statements if-then-else.
Think about that whenever you throw an exception you force your control to be passed to the catch clause. So if you have
if (doSomething() == BAD)
{
//recover or whatever
}
You can easily think of it in terms of try-catch:
try
{
doSomething();
}
catch (Exception e)
{
//recover or do whatever
}
The powerful thing about exception is that you don't have to be in the same body to alter the flow of the program, you can throw an exception whenever you want with the guarantee that control flow will suddently diverge and reach the catch clause. This is powerful but dangerous at the same time since you could have done actions that need some backup at the end, that's why the finally statement exists.
In addition you can model also a while statement without effectively using the condition of it:
while (!finished)
{
//do whatever
}
can become
try
{
while (true)
{
doSomethingThatEventuallyWillThrowAnException();
}
}
catch (Exception e)
{
//loop finished
}

A module developed by a partner caused our application to take a very long time to load. On closer examination, the module was looking for a config file at app startup. This by itself was not too objectionable, but the way in which it was doing it was outrageously bad:
For every file in the app directory, it opened the file and tried to parse it as XML. If a file threw an exception (because it wasn't XML), it caught the exception, squelched it, and tried the next file!
When the partner tested this module, they only had 3 files in the app directory. The bonehead config file search didn't have a noticeable effect on the test app startup. When we added it to our application, there were 100's of files in the app directory, and the app froze for nearly a minute at startup.
To add salt to the wound, the name of the config file the module was searching for was predetermined and constant. There was no need for a file search of any kind.
Genius has its limits. Stupidity is unbounded.

One example would be using exceptions to return a result from a recursive method:
public void Search(Node node, object data)
{
if(node.Data.Equals(data))
{
throw new ResultException(node);
}
else
{
Search(node.LeftChild, data);
Search(node.RightChild, data);
}
}
Doing something like this is a problem for several reasons.
It's completely counter-intuitive. Exceptions are designed for exceptional cases. Something working as intended should (we hope) never be an exceptional scenario.
You can't always rely on an exception being thrown and propagated to you. For example, if the exception-throwing code runs in a separate thread, you'll need some extra code to capture it.
It is a potential performance problem. There is an overhead associated with exceptions and if you throw a lot of them, you might see a performance drop in your application.
There are a few more examples and some interesting discussion on this subject here.
Disclaimer: The code above is adapted from the first sample on that wiki page to turn it into C#.

Related

Is it a good Idea to wrap return values of functions? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Is it a good idea to wrap the return value of the functions in a class. It provides ease of coding and you can avoid try...catch
I'm taking about doing something like this.
public class ResultWrapper
{
public bool Success{get;set;}
public Exception ErrorMessage{get;set;}
public object Result{get;set;} //not object essentially(any type)
public Result()
{
Success=false;
ErrorMessage="";
Result=null;
}
}
public ResultWrapper DoSomething(parameters....)
{
var result=new ResultWrapper()
try
{
}
catch(Exception ex)
{
result.Error=ex;
}
return result;
}
and then calling it like
static void main()
{
var result=DoSomething(parameters...);
if(result.Success)
{
//Carry on with result.Result;
}
else
{
//Log the exception or whatever... result.Error
}
}
EDIT:
consider this
static void main()
{
var result=Login(); //throws an exception
if(result.Success)
{
//retrive the result
//carry on
result=PostSomeStuff(parameter);
if(result.Success)
{
}
else
{
Console.WriteLine("Unable to Post the data.\r\nError: {0}",result.Error.Message);
}
}
else
{
Console.WriteLine("Unable to login.\r\nError: {0}",result.Error.Message);
}
}
isn't it simpler then to wrapping a try..catch outside of each function???
static void main()
{
try
{
var result=Login();
var result1=result=PostSomeStuff(parameter);
// a lot of functions doing seprate things.
}
catch(Exception ex)
{
//what to do...?
}
}
No, this is an anti-pattern. If there is any exception that you don't know how to handle then let it propagate up. Returning exception objects in the return value is a very bad idea when the language has support for exceptions.
If the method is successful it should return the value directly; if it fails it should throw an exception. (Caveat: Some methods might return bool indicating success or failure, and store the result in an out parameter. For example, int.TryParse(), Dictionary<TKey, TValue>.TryGetValue(), etc. Since exceptions can be expensive, some operations might be better suited to simply return a flag indicating failure if failure is expected to be frequent, but this should be a rare occurrence.)
Generally no. There may be specific cases where it's a good idea, but I wouldn't recommend it as a default.
It will make it impossible to allow the exception to "bubble up" until it gets to a good place to handle it. It will make the code harder to understand.
This is awful. Think how many if statement would be added to your code, just to check if an exception was thrown.
Also, think of it this way: if this were a great idea, then the .NET Framework itself would do this. Have you ever seen this pattern anywhere in .NET? I haven't.
You should almost always match the semantics of what the framework does that you are using, otherwise you end up with a weird mish-mash. Soon you have 10 competing coding "standards."

Stack overflow error in console application

I currently have a console application written in C# for production server environment. It's quite simple, but I've been testing it for +- 3 months now on my own server (semi-production, but not a disaster if the program fails). I've been getting stack overflow errors every few weeks or so, though.
Of course, pasting my entire source code here would be quite a long piece, so I will try to explain it the best I can: the program is in an infinite while loop (this is probably the cause of the issue), and it checks every second a few small things and prints to the console every so often (if no activity, every 15min, otherwise up-to every second).
Now why and how can I fix the stack overflow errors? Being able to run it for a couple weeks without issue may seem like a lot, but it is obviously not in a server production environment. My guess is that it's the fact I'm using a while loop, but what alternatives do I have?
Edit: here's a portion of the code:
int timeLoop = 0;
while (true)
{
// If it has been +-10min since last read of messages file, read again
if (timeLoop > 599)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " Reading messages...");
messagesFile = File.ReadAllText(#"messages.cfg");
messages = messagesFile.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
timeLoop = 0;
}
// For each message, check if time specified equals current time, if so say message globally.
foreach (string x in messages)
{
string[] messageThis = x.Split('~');
int typeLoop = 0;
if (messageThis[2] != "no-loop")
typeLoop = Convert.ToInt16(messageThis[2].Remove(0, 5));
DateTime checkDateTime = DateTime.ParseExact(messageThis[0], "HH:mm:ss", null);
if (typeLoop == 0)
{
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
}
else
{
DateTime originalDateTime = checkDateTime;
do
{
checkDateTime = checkDateTime.AddHours(typeLoop);
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
} while (checkDateTime.ToString("HH:mm:ss") != originalDateTime.ToString("HH:mm:ss"));
}
}
timeLoop++;
Thread.Sleep(1000);
}
Also, I forgot that I actually have this code on Github, which probably helps a lot. I know you shouldn't be using any links to code and have them here, so that's why I included the snippet above - but if you are interested in helping me out the repository is located here. Another note - I know that doing it like this is not very accurate on timing - but this is not much of an issue at the moment.
BattleEyeClient.Connect can call itself in some (failing) circumstances, and this method can be called by sayGlobal - so you probably want to change this code block (from line 98):
catch
{
if (disconnectionType == BattlEyeDisconnectionType.ConnectionLost)
{
Disconnect(BattlEyeDisconnectionType.ConnectionLost);
Connect();
return BattlEyeConnectionResult.ConnectionFailed;
}
else
{
OnConnect(loginCredentials, BattlEyeConnectionResult.ConnectionFailed);
return BattlEyeConnectionResult.ConnectionFailed;
}
}
Maybe keep track of how many reconnection attempts you make or transform this section of code so that it is a while loop rather than a recursive call during this failure mode.
Even worse, of course, is if that recursive Connect call succeeds, this catch block then returns BattlEyeConnectionResult.ConnectionFailed which it probably shouldn't.

Best practices for exception handling and safe coding

Say you were calling a method similar to the following, which you know is only ever going to throw one of 2 exceptions:
public static void ExceptionDemo(string input)
{
if (input == null)
throw new ArgumentNullException("input");
if (input.Contains(","))
throw new ArgumentException("input cannot contain the comma character");
// ...
// ... Some really impressive code here
// ...
}
A real life example of a method which does this is Membership.GetUser (String)
Which of the following would you use to call the method and handle the exceptions:
Method 1 (check the input param first first)
public static void Example1(string input)
{
// validate the input first and make sure that the exceptions could never occur
// no [try/catch] required
if (input != null && !input.Contains(","))
{
ExceptionDemo(input);
}
else
{
Console.WriteLine("input cannot be null or contain the comma character");
}
}
Method 2 (wrap the call in a try / catch)
public static void Example2(string input)
{
// try catch block with no validation of the input
try
{
ExceptionDemo(input);
}
catch (ArgumentNullException)
{
Console.WriteLine("input cannot be null");
}
catch (ArgumentException)
{
Console.WriteLine("input cannot contain the comma character");
}
}
I've had both methods taught over the years and wondered what the general best practise was for this scenario.
Update
Several posters were focusing on the method throwing the exceptions and not the way these exceptions were being handled, so I've provided an example of a .Net Framework method which behaves in the same way (Membership.GetUser (String))
So, to clarify my question, if you we're calling Membership.GetUser(input) how would you handle the possible exceptions, Method 1, 2 or something else?
Thanks
It depends, but generally, neither method presented is good. As has been said, in the first case, you are duplicating code. In the second, you are catching the exception without actually doing anything about it - not even rethrowing, just swallowing it. If you want just to log it or display some message, normally you should implement a global handler/logger using AppDomain.UnhandledException and do it there; this way, you don't have to pollute your code with unnecessary try/catch blocks.
The real question here is whether or not input being null or containing ',' is really an exceptional behavior in your specific case - e.g. if this is some GUI-entered string, then this should normally not result in an exception throw (end-user mistakes should be expected) and should be handled appropriately (e.g. with a warning to re-entry the input). In such case, using if statements to validate the input is the proper way. However, if input being null or containing ',' is an actual exceptional behavior (say, an API problem which indicates something's broken or missing) then throwing exception is ok. In this case, you can simply call ExceptionDemo(input) without try/catch. If you want to actually do something about the exception (e.g. change the input in some way), then use try/catch.
Callers should not assume anything about code they're calling.
Your first example is bad, because you're duplicating code: the caller performs almost (string.INOE() vs string == null) the same check as the callee (until either of them changes).
The second example is extremely bad as it ignores the thrown exceptions and gives its own interpretation to them.
As usual: it depends. If you have a properly layered application where the method calls are in your UI layer, you do want to just catch the exception the method throws: you'll want to display those errors to the user.
It depends on how many times ExceptionDemo is called and who it is exposed to. If it was used extensively, you wouldn't want to check the conditions before calling ExceptionDemo, when you know (and document) that ExceptionDemo does the checks anyway.
Given the return type is void, what about changing ExceptionDemo to have no effect if the input is wrong?
(Did you notice that you are stricter in Method 1 - the empty string is not a valid input, but in Method 2 it is)
I would recommend standard and generic structure as below :
public static void Operation(object input)
{
try
{
ValidateInput(input);
//Do Operation
}
catch (MySpecificException subSubExceptionType) //Catch most specific exceptions
{
//Log or process exception
throw;
}
catch (MySpecificException subExceptionType) //Catch specific exception
{
//Log or process exception
}
catch (Exception exceptionType) //Catch most generic exception
{
//Log or process exception
}
finally
{
//Release the resources
}
}
private static void ValidateInput(object input)
{
if(input == null)
throw new NoNullAllowedException();
//Check if properties of input are as expected. If not as expected then throw specific exception with specific message
}

Additional try statement in catch statement - code smell?

Situation:
My application need to process the first step in the business rules (the initial try-catch statement). If an certain error occurs when the process calls the helper method during the step, I need to switch to a second process in the catch statement. The back up process uses the same helper method. If an same error occurs during the second process, I need to stop the entire process and throw the exception.
Implementation:
I was going to insert another try-catch statement into the catch statement of the first try-catch statement.
//run initial process
try
{
//initial information used in helper method
string s1 = "value 1";
//call helper method
HelperMethod(s1);
}
catch(Exception e1)
{
//backup information if first process generates an exception in the helper method
string s2 = "value 2";
//try catch statement for second process.
try
{
HelperMethod(s2);
}
catch(Exception e2)
{
throw e2;
}
}
What would be the correct design pattern to avoid code smells in this implementation?
I caused some confusion and left out that when the first process fails and switches to the second process, it will send different information to the helper method. I have updated the scenario to reflect the entire process.
If the HelperMethod needs a second try, there is nothing directly wrong with this, but your code in the catch tries to do way too much, and it destroys the stacktrace from e2.
You only need:
try
{
//call helper method
HelperMethod();
}
catch(Exception e1)
{
// maybe log e1, it is getting lost here
HelperMethod();
}
I wouldn't say it is bad, although I'd almost certainly refactor the second block of code into a second method, so keep it comprehensible. And probably catch something more specific than Exception. A second try is sometimes necessary, especially for things like Dispose() implementations that might themselves throw (WCF, I'm looking at you).
The general idea putting a try-catch inside the catch of a parent try-catch doesn't seem like a code-smell to me. I can think of other legitimate reasons for doing this - for instance, when cleaning up an operation that failed where you do not want to ever throw another error (such as if the clean-up operation also fails). Your implementation, however, raises two questions for me: 1) Wim's comment, and 2) do you really want to entirely disregard why the operation originally failed (the e1 Exception)? Whether the second process succeeds or fails, your code does nothing with the original exception.
Generally speaking, this isn't a problem, and it isn't a code smell that I know of.
With that said, you may want to look at handling the error within your first helper method instead of just throwing it (and, thus, handling the call to the second helper method in there). That's only if it makes sense, but it is a possible change.
Yes, a more general pattern is have the basic method include an overload that accepts an int attempt parameter, and then conditionally call itself recursively.
private void MyMethod (parameterList)
{ MyMethod(ParameterList, 0)l }
private void MyMethod(ParameterList, int attempt)
{
try { HelperMethod(); }
catch(SomeSpecificException)
{
if (attempt < MAXATTEMPTS)
MyMethod(ParameterList, ++attempt);
else throw;
}
}
It shouldn't be that bad. Just document clearly why you're doing it, and most DEFINITELY try catching a more specific Exception type.
If you need some retry mechanism, which it looks like, you may want to explore different techniques, looping with delays etc.
It would be a little clearer if you called a different function in the catch so that a reader doesn't think you're just retrying the same function, as is, over again. If there's state happening that's not being shown in your example, you should document it carefully, at a minimum.
You also shouldn't throw e2; like that: you should simply throw; if you're going to work with the exception you caught at all. If not, you shouldn't try/catch.
Where you do not reference e1, you should simply catch (Exception) or better still catch (YourSpecificException)
If you're doing this to try and recover from some sort of transient error, then you need to be careful about how you implement this.
For example, in an environment where you're using SQL Server Mirroring, it's possible that the server you're connected to may stop being the master mid-connection.
In that scenario, it may be valid for your application to try and reconnect, and re-execute any statements on the new master - rather than sending an error back to the caller immediately.
You need to be careful to ensure that the methods you're calling don't have their own automatic retry mechanism, and that your callers are aware there is an automatic retry built into your method. Failing to ensure this can result in scenarios where you cause a flood of retry attempts, overloading shared resources (such as Database servers).
You should also ensure you're catching exceptions specific to the transient error you're trying to retry. So, in the example I gave, SqlException, and then examining to see if the error was that the SQL connection failed because the host was no longer the master.
If you need to retry more than once, consider placing an 'automatic backoff' retry delay - the first failure is retried immediately, the second after a delay of (say) 1 second, then doubled up to a maximum of (say) 90 seconds. This should help prevent overloading resources.
I would also suggest restructuring your method so that you don't have an inner-try/catch.
For example:
bool helper_success = false;
bool automatic_retry = false;
//run initial process
try
{
//call helper method
HelperMethod();
helper_success = true;
}
catch(Exception e)
{
// check if e is a transient exception. If so, set automatic_retry = true
}
if (automatic_retry)
{ //try catch statement for second process.
try
{
HelperMethod();
}
catch(Exception e)
{
throw;
}
}
Here's another pattern:
// set up state for first attempt
if(!HelperMethod(false)) {
// set up state for second attempt
HelperMethod(true);
// no need to try catch since you're just throwing anyway
}
Here, HelperMethod is
bool HelperMethod(bool throwOnFailure)
and the return value indicates whether or not success occurred (i.e., false indicates failure and true indicates success). You could also do:
// could wrap in try/catch
HelperMethod(2, stateChanger);
where HelperMethod is
void HelperMethod(int numberOfTries, StateChanger[] stateChanger)
where numberOfTries indicates the number of times to try before throwing an exception and StateChanger[] is an array of delegates that will change the state for you between calls (i.e., stateChanger[0] is called before the first attempt, stateChanger[1] is called before the second attempt, etc.)
This last option indicates that you might have a smelly setup though. It looks like the class that is encapsulating this process is responsible for both keeping track of state (which employee to look up) as well as looking up the employee (HelperMethod). By SRP, these should be separate.
Of course, you need to a catch a more specific exception than you currently are (don't catch the base class Exception!) and you should just throw instead of throw e if you need to rethrow the exception after logging, cleanup, etc.
You could emulate C#'s TryParse method signatures:
class Program
{
static void Main(string[] args)
{
Exception ex;
Console.WriteLine("trying 'ex'");
if (TryHelper("ex", out ex))
{
Console.WriteLine("'ex' worked");
}
else
{
Console.WriteLine("'ex' failed: " + ex.Message);
Console.WriteLine("trying 'test'");
if (TryHelper("test", out ex))
{
Console.WriteLine("'test' worked");
}
else
{
Console.WriteLine("'test' failed: " + ex.Message);
throw ex;
}
}
}
private static bool TryHelper(string s, out Exception result)
{
try
{
HelperMethod(s);
result = null;
return true;
}
catch (Exception ex)
{
// log here to preserve stack trace
result = ex;
return false;
}
}
private static void HelperMethod(string s)
{
if (s.Equals("ex"))
{
throw new Exception("s can be anything except 'ex'");
}
}
}
Another way is to flatten the try/catch blocks, useful if you're using some exception-happy API:
public void Foo()
{
try
{
HelperMethod("value 1");
return; // finished
}
catch (Exception e)
{
// possibly log exception
}
try
{
HelperMethod("value 2");
return; // finished
}
catch (Exception e)
{
// possibly log exception
}
// ... more here if needed
}
An option for retry (that most people will probably flame) would be to use a goto. C# doesn't have filtered exceptions but this could be used in a similar manner.
const int MAX_RETRY = 3;
public static void DoWork()
{
//Do Something
}
public static void DoWorkWithRetry()
{
var #try = 0;
retry:
try
{
DoWork();
}
catch (Exception)
{
#try++;
if (#try < MAX_RETRY)
goto retry;
throw;
}
}
In this case you know this "exception" probably will happen so I would prefer a simple approach an leave exceptions for the unknown events.
//run initial process
try
{
//initial information used in helper method
string s1 = "value 1";
//call helper method
if(!HelperMethod(s1))
{
//backup information if first process generates an exception in the helper method
string s2 = "value 2";
if(!HelperMethod(s2))
{
return ErrorOfSomeKind;
}
}
return Ok;
}
catch(ApplicationException ex)
{
throw;
}
I know that I've done the above nested try catch recently to handle decoding data where two third party libraries throw exceptions on failure to decode (Try json decode, then try base64 decode), but my preference is to have functions return a value which can be checked.
I generally only use the throwing of exceptions to exit early and notify something up the chain about the error if it's fatal to the process.
If a function is unable to provide a meaningful response, that is not typically a fatal problem (Unlike bad input data).
It seems like the main risk in nested try catch is that you also end up catching all the other (maybe important) exceptions that might occur.

Writing code to fire the last method to throw an exception in a multi-threaded web app

I was writing some try-catch blocks for various methods today, and thought to myself it would be good to have utility method which would automatically call the method again for a number of times specified in a parameter, at a certain time.
However, I thought to myself, the method/property etc which will cause an exception will be at the top of the stacktrace (do property calls get put on the stacktrace?) in a single threaded application (so an application with no code relating to threading). So I can simply get the method name at the top and dynamically call it again.
So I would have code like:
string s = StackTrace.GetFrame(0).GetMethodName; (I can't remember the exact syntax).
With this method, I can execute it using an activator or one of several other ways.
But in a multi-threaded application, I could have several methods firing at once and I wouldn't know which one finishes first/last. So I can't expect a method for which I write a try-catch block to be at the top of the stack.
How would I go about achieving this?
Please don't do this. It's a really, really, really, really, really bad idea.
Maybe not as bad as deleting files randomly, if the hard drive runs out of room - but just about as bad.
While I question the need for an auto retrying mechanism (does randomly retrying really help you out in so many situations that you need a utility method?) - using StackTrace and Reflection is, at best, a terribly complicated solution.
Not that I suggest that anyone actually use this code, but I'd probably go with a delegate based approach to this particular problem:
public static class Extensions {
public static void Try(this Action a, int maxTries) {
new (Func<bool>(() => { a(); return true; })).Try(maxTries);
}
public static TResult Try<TResult>(this Func<TResult> f, int maxTries) {
Exception lastException = null;
for (int i = 0; i < maxTries; i++) {
try {
return f();
} catch (Exception ex) {
lastException = ex;
}
}
throw lastException;
}
}
Usage is a bit unorthodox, but fairly clear I think:
// Set a property
new Action(() => myObject.Property = 5).Try(5);
// With a return value
var count = new Func<int>(() => myList.Count).Try(3);
You can't inline a lambda to a method, but you could have a somewhat fluent interface:
Utilities.Try(
() => MyObject.Property = 5
).Repeat(5);
And multi line methods:
Utilities.Try(() => {
MyObject.Property1 = 5;
MyObject.Property2 = 6;
MyObject.Property3 = 7;
}).Repeat(5);
Mark's code is probably better, but here's mine...
If you really want to do something like this, I'd use code something like this. Yes, you still have to manually call it, but your idea of indiscriminately retrying ALL excepting methods is a really, really bad idea.
public class TryAgain
{
public delegate void CodeToTryAgain ();
public static void Repeat<E>(int count, CodeToTryAgain code) where E : Exception
{
while (count-- > 0)
{
try
{
code();
return;
}
catch (E ex)
{
Console.WriteLine("Caught an {0} : {1}", typeof(E).Name, ex.Message);
// ignoring it!
}
}
}
}
And then you'd call your failing method, ThrowTwice, or whatever you want to do, like this:
TryAgain.Repeat<MyException>(5, delegate()
{
ThrowTwice();
});
In this example, the Repeat method will ignore all exceptions of type MyException, trying to call ThrowTwice up to 5 times...
You can add your own sleeping and time-outs, and whatever.

Categories

Resources