7
\$\begingroup\$

I wrote something to the effect of a try catch finally statement helper in functional style so that I can shorten much of the code I'm writing for my Service Layer that connects to an SQL database.

Because of that, I found myself needing to code up a lot of try catch statements. I found this article this article on a functional exception handling and looked at the author's Bitbucket source and was inspired to write the following with a differing style from that of the author but, suiting my purposes. I'm certainly not an expert and I could be totally wrong in my approach here. I'm looking for "yes" or "no" and "here is why".

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Common.Helper
{
    public static class FunctionalHelpers
    {
        public static void TryCatch<TE>(Action tryAction, Action<Exception> handler)
          where TE : Exception
        {
            try { tryAction(); }
            catch (TE ex)
            {
                handler(ex);
            }
        }

        public static void TryCatch<TArg, TE>(Action<TArg> tryAction, TArg args, Action<Exception> handler)
          where TE : Exception
        {
            try { tryAction(args); }
            catch (TE ex)
            {
                handler(ex);
            }
        }

        public static void TryCatchFinally<TE>(Action tryAction, Action<Exception> CatchAction, Action FinallyAction)
            where TE : Exception
        {
            try
            {
                tryAction();
            }
            catch (TE t)
            {
                CatchAction(t);
            }
            finally
            {
                FinallyAction();
            }
        }

        public static void TryCatchFinallyUsing<TE, TUsing>(Action<TUsing> tryAction, Action<Exception> CatchAction, Action<TUsing> FinallyAction, TUsing arg)
        where TE : Exception
        where TUsing : IDisposable
        {
            using (arg)
            {
                try
                {
                    tryAction(arg);
                }
                catch (TE t)
                {
                    CatchAction(t);
                }
                finally
                {
                    FinallyAction(arg);
                }
            }
        }

        public static void TryCatchFinallyUsing<TE1, TE2, TUsing>(Action<TUsing> tryAction, Action<TE1> CatchHandler1, Action<TE2> CatchHandler2, Action<TUsing> FinallyAction, TUsing arg)
            where TE1 : Exception
            where TE2 : Exception
            where TUsing : IDisposable
        {
            using (arg)
            {
                try
                {
                    tryAction(arg);
                }
                catch (TE1 t)
                {
                    CatchHandler1(t);
                }
                catch (TE2 t)
                {
                    CatchHandler2(t);
                }
                finally
                {
                    FinallyAction(arg);
                }
            }
        }

        public static void TryCatchFinallyUsing<TE1, TE2, TE3, TUsing>(Action<TUsing> tryAction, Action<Exception> CatchHandler1, Action<Exception> CatchHandler2, Action<Exception> CatchHandler3, Action<TUsing> FinallyAction, TUsing arg)
            where TE1 : Exception
            where TE2 : Exception
            where TE3 : Exception
            where TUsing : IDisposable
        {
            using (arg)
            {
                try
                {
                    tryAction(arg);
                }
                catch (TE1 t)
                {
                    CatchHandler1(t);
                }
                catch (TE2 t)
                {
                    CatchHandler2(t);
                }
                catch (TE3 t)
                {
                    CatchHandler3(t);
                }
                finally
                {
                    FinallyAction(arg);
                }
            }
        }

        public static void TryCatchFinally<TArg, TE>(Action<TArg> tryAction, TArg arg, Action<Exception> CatchAction, Action FinallyAction)
            where TE : Exception
        {
            try
            {
                tryAction(arg);
            }
            catch (TE t)
            {
                CatchAction(t);
            }
            finally
            {
                FinallyAction();
            }
        }

        public static void TryCatch<T1>(Action tryAction, Action<Exception> handler, Action FinallyAction)
            where T1 : Exception
        {
            try
            {
                tryAction();
            }
            catch (T1 ex)
            {
                handler(ex);
            }
            finally
            {
                FinallyAction();
            }
        }

        public static void TryCatchFinally<T1, TF>(Action tryAction, Action<Exception> handler, Action<TF> finallyAction, TF FinallyArg)
            where T1 : Exception
        {
            try
            {
                tryAction();
            }
            catch (T1 ex)
            {
                handler(ex);
            }
            finally
            {
                finallyAction(FinallyArg);
            }
        }

        public static void TryCatchFinally<TE1, TE2, TF>(Action tryAction, Action<Exception> handler1, Action<Exception> handler2, Action<TF> finallyAction, TF FinallyArg)
            where TE1 : Exception
            where TE2 : Exception
        {
            try
            {
                tryAction();
            }
            catch (TE1 ex)
            {
                handler1(ex);
            }
            catch (TE2 ex)
            {
                handler2(ex);
            }
            finally
            {
                finallyAction(FinallyArg);
            }
        }


        public static void TryCatchFinally<TE1, TE2, TE3, TF>(Action tryAction, Action<Exception> handler1, Action<Exception> handler2, Action<Exception> handler3, Action<TF> finallyAction, TF FinallyArg)
            where TE1 : Exception
            where TE2 : Exception
            where TE3 : Exception
        {
            try
            {
                tryAction();
            }
            catch (TE1 ex)
            {
                handler1(ex);
            }
            catch (TE2 ex)
            {
                handler2(ex);
            }
            catch (TE3 ex)
            {
                handler3(ex);
            }
            finally
            {
                finallyAction(FinallyArg);
            }
        }
    }
}
\$\endgroup\$

1 Answer 1

9
\$\begingroup\$

There are some smaller issues in your code, which I will mention later. But the main issue I see is that it's quite useless, since it doesn't make your code any shorter.

If you compare:

try
{
    /* some code */
}
catch (SomeException ex)
{
    /* more code */
}

with

FunctionalHelpers.TryCatch<SomeException>(
    () => /* some code */,
    ex => /* more code */);

then the latter might look shorter, but that's mostly an illusion. It's more complicated, it's actually longer (if you count the characters) and you could also write the original code like this:

try { /* some code */ }
catch (SomeException ex)
{ /* more code */ }

Though I'm not saying you should do that, this code looks terrible.

The point of the article you linked to was to be able to handle several different exceptions with the same code without repeating. Your methods can't do that.


Now to the minor points:

public static void TryCatch<TE>(Action tryAction, Action<Exception> handler)

You should use Action<TE> instead. This way, you can easily access properties that are specific to that type of exception.

public static void TryCatch<TArg, TE>(Action<TArg> tryAction, TArg args, Action<Exception> handler)

I don't see much point in having overloads with args. It's usually much easier to use closures (though slightly less performant).

public static void TryCatchFinallyUsing<TE, TUsing>(Action<TUsing> tryAction, Action<Exception> CatchAction, Action<TUsing> FinallyAction, TUsing arg)

It seems you missed another point the article made. If you have TUsing as a simple parameter and the code that creates that object throws, it won't be caught by your CatchAction. You should have Func<TUsing> instead.

Also, you should consistently name parameters using camelCase, not PascalCase.

public static void TryCatch<T1>(Action tryAction, Action<Exception> handler, Action FinallyAction)

This method should be called TryCatchFinally.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ +1. For "doesn't make it shorter." And I'd throw in "doesn't make it easier" for good measure. Further, to quote the ref. article: `The idea is that it saves copy-and-paste on the code in the catch block, where that code is all the same.' BF deal. How about a good IDE, code snippets, code completion, typing skills, good OO class design, etc., etc., and etc. \$\endgroup\$
    – radarbob
    Commented Mar 2, 2013 at 18:59
  • 2
    \$\begingroup\$ I know this is an old post but with the recent changes to .net support a more functional approach to development something "like" this might make sense. If you are unable to make the full switch to F# you can at least get some semblance of a functional chaining style. \$\endgroup\$
    – Bronumski
    Commented Mar 29, 2018 at 16:28
  • \$\begingroup\$ Not sure we can directly say it wont reduce the code. Below code is reducing so much code for me when I want to disable button then execute handler and enable after that. Functions.ExecuteButtonClickWithEnableAndDisable(TestConnectionButton, () =>{ }); \$\endgroup\$ Commented Aug 17, 2018 at 14:39
  • \$\begingroup\$ @JoyGeorgeKunjikkuru I wasn't talking about that style of code in general, I was talking about the specific code above. \$\endgroup\$
    – svick
    Commented Aug 17, 2018 at 16:40
  • \$\begingroup\$ With c# 6 it is shorter, with using static. \$\endgroup\$
    – Luis
    Commented Nov 12, 2018 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.