How to Avoid the Nesting? Extracting the nested part as a new method will always work for any arbitrarily nested Try-Catch-Finally block. So this is one trick that you can always use to improve the code.
I actually don't think there's anything inherently wrong about nested Try / Catch blocks, except that they can be difficult to navigate and are likely a sign that you could do some refactoring (the inner Try / Catch into its own method, for example).
Nested try block is a block in which we can implement one try catch block into another try catch block. The requirement of nested try-catch block arises when an exception occurs in the inner try-catch block is not handled by the inner catch blocks then the outer try-catch blocks are checked for that exception.
When a try catch block is present in another try block then it is called the nested try catch block. Each time a try block does not have a catch handler for a particular exception, then the catch blocks of parent try block are inspected for that exception, if match is found that that catch block executes.
As far as possible, don't use exceptions for control flow or unexceptional circumstances.
But to answer your question directly (assuming all the exception-types are the same):
Func<double>[] calcs = { calc1, calc2, calc3 };
foreach(var calc in calcs)
{
try { return calc(); }
catch (CalcException){ }
}
throw new NoCalcsWorkedException();
You could flatten out the nesting by putting it into a method like this:
private double calcStuff()
{
try { return calc1(); }
catch (Calc1Exception e1)
{
// Continue on to the code below
}
try { return calc2(); }
catch (Calc2Exception e1)
{
// Continue on to the code below
}
try { return calc3(); }
catch (Calc3Exception e1)
{
// Continue on to the code below
}
throw new NoCalcsWorkedException();
}
But I suspect the real design problem is the existence of three different methods that do essentially the same thing (from the caller's perspective) but throw different, unrelated exceptions.
This is assuming the three exceptions are unrelated. If they all have a common base class, it'd be better to use a loop with a single catch block, as Ani suggested.
Just to offer an "outside the box" alternative, how about a recursive function...
//Calling Code
double result = DoCalc();
double DoCalc(int c = 1)
{
try{
switch(c){
case 1: return Calc1();
case 2: return Calc2();
case 3: return Calc3();
default: return CalcDefault(); //default should not be one of the Calcs - infinite loop
}
}
catch{
return DoCalc(++c);
}
}
NOTE: I am by no means saying that this is the best way to get the job done, just a different way
Try not to control logic based on exceptions; note also that exceptions should be thrown only in exceptional cases. Calculations in most cases should not throw exceptions unless they access external resources or parse strings or something. Anyway in the worst case follow the TryMethod style (like TryParse()) to encapsulate exception logic and make your control flow maintainable and clean:
bool TryCalculate(out double paramOut)
{
try
{
// do some calculations
return true;
}
catch(Exception e)
{
// do some handling
return false;
}
}
double calcOutput;
if(!TryCalc1(inputParam, out calcOutput))
TryCalc2(inputParam, out calcOutput);
Another variation utilizing the Try pattern and combining list of methods instead of nested if:
internal delegate bool TryCalculation(out double output);
TryCalculation[] tryCalcs = { calc1, calc2, calc3 };
double calcOutput;
foreach (var tryCalc in tryCalcs.Where(tryCalc => tryCalc(out calcOutput)))
break;
and if the foreach is a little complicated you can make it plain:
foreach (var tryCalc in tryCalcs)
{
if (tryCalc(out calcOutput)) break;
}
Create a list of delegates to your calculation functions and then have a while loop to cycle through them:
List<Func<double>> calcMethods = new List<Func<double>>();
// Note: I haven't done this in a while, so I'm not sure if
// this is the correct syntax for Func delegates, but it should
// give you an idea of how to do this.
calcMethods.Add(new Func<double>(calc1));
calcMethods.Add(new Func<double>(calc2));
calcMethods.Add(new Func<double>(calc3));
double val;
for(CalcMethod calc in calcMethods)
{
try
{
val = calc();
// If you didn't catch an exception, then break out of the loop
break;
}
catch(GenericCalcException e)
{
// Not sure what your exception would be, but catch it and continue
}
}
return val; // are you returning the value?
That should give you a general idea of how to do it (i.e. it's not an exact solution).
This looks like a job for... MONADS! Specifically, the Maybe monad. Start with the Maybe monad as described here. Then add some extension methods. I wrote these extension methods specifically for the problem as you described it. The nice thing about monads is you can write the exact extension methods needed for your situation.
public static Maybe<T> TryGet<T>(this Maybe<T> m, Func<T> getFunction)
{
// If m has a value, just return m - we want to return the value
// of the *first* successful TryGet.
if (m.HasValue)
{
return m;
}
try
{
var value = getFunction();
// We were able to successfully get a value. Wrap it in a Maybe
// so that we can continue to chain.
return value.ToMaybe();
}
catch
{
// We were unable to get a value. There's nothing else we can do.
// Hopefully, another TryGet or ThrowIfNone will handle the None.
return Maybe<T>.None;
}
}
public static Maybe<T> ThrowIfNone<T>(
this Maybe<T> m,
Func<Exception> throwFunction)
{
if (!m.HasValue)
{
// If m does not have a value by now, give up and throw.
throw throwFunction();
}
// Otherwise, pass it on - someone else should unwrap the Maybe and
// use its value.
return m;
}
Use it like so:
[Test]
public void ThrowIfNone_ThrowsTheSpecifiedException_GivenNoSuccessfulTryGet()
{
Assert.That(() =>
Maybe<double>.None
.TryGet(() => { throw new Exception(); })
.TryGet(() => { throw new Exception(); })
.TryGet(() => { throw new Exception(); })
.ThrowIfNone(() => new NoCalcsWorkedException())
.Value,
Throws.TypeOf<NoCalcsWorkedException>());
}
[Test]
public void Value_ReturnsTheValueOfTheFirstSuccessfulTryGet()
{
Assert.That(
Maybe<double>.None
.TryGet(() => { throw new Exception(); })
.TryGet(() => 0)
.TryGet(() => 1)
.ThrowIfNone(() => new NoCalcsWorkedException())
.Value,
Is.EqualTo(0));
}
If you find yourself doing these sorts of calculations often, the maybe monad should reduce the amount of boilerplate code you have to write while increasing the readability of your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With