4

I have several C# methods that I want to wrap in a try-catch block. Each function will have the same logic for the catch. Is there an elegant way to add a decorator to each of these functions so they are all wrapped with the same try/catch block? I don't want to add the try/catch block to all of these functions.

Example:

public void Function1(){
   try {
     do something
   }catch(Exception e) {
      //a BUNCH of logic that is the same for all functions
   }
}

public void Function2() {
   try {
     do something different
   }catch(Exception e) {
      //a BUNCH of logic that is the same for all functions
   }
}
void
  • 881
  • 3
  • 20
  • 27
Henley
  • 21,258
  • 32
  • 119
  • 207
  • Can you show your code... – Soner Gönül Mar 28 '13 at 14:38
  • 6
    Why not just try/catch each and send the exception to a common static function? – Joel Etherton Mar 28 '13 at 14:38
  • @JoelEtherton How would I go about doing that, do you have an example? – Henley Mar 28 '13 at 14:42
  • Why aren't you letting your excpetions bubble up and get handled (logged) by a global exception handler? – Kirk Woll Mar 28 '13 at 14:45
  • use [AOP](http://en.wikipedia.org/wiki/Aspect-oriented_programming) see for example the following code: http://www.rhyous.com/2012/06/15/aop-implementing-try-catch-in-csharp-with-postsharp/ code is as simple as adding an attribute to the functions. http://stackoverflow.com/questions/4999144/aspect-oriented-programing-aop-solutions-for-c-sharp-net-and-their-features – Nahum Mar 28 '13 at 14:40

2 Answers2

15

What about some functional solution to this? Notice I don't swallow exceptions and use throw; statement, that will re-throw exception keeping its original stack trace. Don't silently swallow exceptions - it's considered to be a very bad practice and the debugging code gets horrible.

void Main()
{
    WrapFunctionCall( () => DoSomething(5));
    WrapFunctionCall( () => DoSomethingDifferent("tyto", 4));
}

public void DoSomething(int v){ /* logic */}

public void DoSomethingDifferent(string v, int val){ /* another logic */}

public void WrapFunctionCall(Action function) 
{
    try
    {
        function();
    }
    catch(Exception e)
    {
         //a BUNCH of logic that is the same for all functions
         throw;
    }
}

If you need to return some value, the signature for WrapFunctionCall method will change

void Main()
{
    var result = WrapFunctionCallWithReturn( () => DoSomething(5));
    var differentResult = WrapFunctionCallWithReturn( () => DoSomethingDifferent("tyto", 4));
}

public int DoSomething(int v){ return 0; }

public string DoSomethingDifferent(string v, int val){ return "tyto"; }

public T WrapFunctionCallWithReturn<T>(Func<T> function) 
{
    try
    {
        return function();
    }
    catch(Exception e)
    {
        //a BUNCH of logic that is the same for all functions
        throw;
    }
}
Cosmin
  • 2,365
  • 2
  • 23
  • 29
Ilya Ivanov
  • 23,148
  • 4
  • 64
  • 90
  • Thanks! Your code is useful! I did hit a problem where if all functions (except WrapFunctionCallWithReturn) took ref parameters it would result in an error: "Cannot use ref or out parameter inside an anonymous method...". We solved it by making a temporary and then assigning it back after the call; is there a way to use this solution with ref or out parameters? – A.J. May 26 '15 at 19:17
  • and with async? which you prefer: `var result = await WrapFunctionCallWithReturn( () => DoSomething(5));` `var result = WrapFunctionCallWithReturn( () => await DoSomething(5));` – Fantastory Jul 13 '16 at 12:18
  • i get it: `var result = await WrapFunctionCallWithReturn( () => DoSomething(5));` is needed - await must be inside of the try catch – Fantastory Jul 13 '16 at 12:21
  • saved a lot of time! – Pratik Bhattacharya Aug 06 '19 at 16:23
  • Totally irrelevant, but: does "tyto" have any value to you as placeholder string or is it just random letters? (this was an excuse to say 'thank you for this answer!' BTW) – Sebastián Vansteenkiste Apr 22 '20 at 18:37
2

This is Joel Etherton's comment paraphrased as an answer. Note that this isn't the best solution (see Ilya Ivanov's answer for better a solution).
But it's simple and if I read your question correctly it's exactly what you asked for:

void errorHandling(Exception e)
{
  // Your BUNCH of logic
}

public void Function1(){
   try {
     do something
   }catch(Exception e) {
      errorHandling(e);
   }
}

public void Function2() {
   try {
     do something different
   }catch(Exception e) {
      errorHandling(e);
   }
}
void
  • 881
  • 3
  • 20
  • 27