High order approach for exceptions in C #

Hi everyone, I was thinking about passing method blocks as arguments to helper classes that were created in exception handling, but this is one of those things that is intuitive and I would like to present it for criticism, understanding or advice.

I would like to point out that this is NOT how I do all the exception handling, but there are cases where I find this structure more "readable".

For example, I have a scenario where I show a preview image, but if that fails (this is a real scenario when I preview images and some GIF / BMP formats cannot be previewed), this is just a scenario where I instead of preview view, display an alternate image. The try / catch code block looks like this:

  try
  {
        alternatePreviewImage.SetSource(fs);
  }
  catch (Exception ex) {
        requiresSpecialPreview = false;
        previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative));
  }

      

So, I am using a helper class that takes a method parameter so that it looks like this:

  if(!ErrorHelper.RunWithSuccessNotify(()=> alternatePreviewImage.SetSource(fs))){
        requiresSpecialPreview = false;
        previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative));                             
  }

      

ErrorHelper.RunWithSuccessNotify is pretty simple:

public static bool RunWithSuccessNotify(Action code) {
    bool success = true;
    try
    {
        code();
    }
    catch (Exception ex)
    {
        success = false;
    }

    return success;
}

      

Let me stress again that this is useful for these low impact scenarios as well as others where I can suppress the exception:

public static void RunWithErrorSuppression(Action code) {
    try
    {
        code();
    }
    catch (Exception ex)
    {
        // pass
    }
}

      

The approach can be more detailed to account for the exception:

    public static void ExecuteWithLogging(Action code, Action<Exception> handles) {
        try
        {
            code();
        }
        catch (Exception ex)
        {
            handles(ex);
        }
    }

      

So what are the thoughts on this set of tactics for centralizing exception handling? If this is a bad direction, are there specific reasons why it might get you in trouble?

+2


source to share


6 answers


The main problem I would run into with this approach is catching Exception

is generally considered bad. If there was some way to specify what type of exception to catch, I could buy it, but I believe it needs to be specified at compile time. I also wouldn't feel completely comfortable with catching all exceptions and rebuilding those that don't match.



Remember that when you catch an exception, you are essentially saying that you can handle the error in some meaningful way. Obviously, the code above cannot handle StackOverflowException

or MissingMethodException

.

+3


source


Don't catch all exceptions, parameterize the one you want:

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

namespace ProvaException
{
    class Program
    {
        static void Main(string[] args)
        {

            int a = doWithException<int>(divide, 0, typeof(DivideByZeroException), x => 300);
            Console.WriteLine(a);
            Console.ReadKey();
        }

        public static int divide(int b)
        {
            return 10 / b;
        }

        public static T doWithException<T>(Func<T, T> a, T param1, Type exType, Func<Exception, T> handFunction) {
            try
            {
                return a(param1);
            }
            catch(Exception ex) {
                if(exType.Equals(ex.GetType())) {
                     return handFunction(ex);
                }
                else 
                    throw ex;
            }
        }
    }
}

      

Not very similar to C #, but can be useful in the same case (when you want to abstract from exception handling).



You need to write a different type signature for each type of function, because C # does not support currying. Vinyl boring .: D

It's not a very neat solution, but it does give you a hint on how things work in functional languages. Very fun to learn.

+1


source


Hello, I don't know if it scales well, but at the moment my team is using it in our measurement software to handle a special exception (e.g. communication with some measurement device) and restart the measurement in this case.

It currently works well, especially in cases where an important / non-repetitive piece of code is in a function (Action parameter) that is called and does not handle exceptions.

The best case is that they can even be nested and the main code is readable.

On the other hand, you are hiding what exactly your exception handling is doing behind the function name, so it must be simple or straightforward to be understood only by the function name, otherwise you are confusing something from future readers of your code (you included yourself)

0


source


My initial thought is simply that passing complex anonymous delegates around smells bad. Nothing prevents someone from dumping the anonymous delegate with complex logic into the ErrorHelper methods. This kind of logic becomes difficult to test. I would prefer that the logic is passed only in the object, which seems to me to be a clearer method. To me, anonymous delegates (and lambdas) are for very simple logical extensibility, like comparison logic. The anonymous delegate mechanic is powerful and can be used for other purposes, but with great power comes great responsibility. =)

What you achieve with your technique is the ability to cleanly change your exception handling strategy at runtime. But is this really a requirement?

0


source


Take a look at THIS and maybe drop the ol reflector a bit. It seems to me that the same thing is done there, but perhaps in a more complete way ... It seems very strong ...

0


source


If I figured out what you are trying to do, then it seems awful to me as a standard error management pattern. It's a warning sign right there as it took me a while to figure out your idea.

Unless there is a compelling reason, the code should be explicitly available in the method for any maintenance developer to view and modify, and not be passed from elsewhere. Just because a function exists does not mean that it is useful in most situations. In this case, I don't see any benefit from obfuscation.

BTW, I think you are nailing the corpse to the wall by catching the System.Exception . The normal rule of thumb is not to throw an exception unless you know what an exception is and / or need to know the details of an exception for some reason.

A commonly used pattern for recovering from an unknown exception looks like this:

bool exceptionHappened = true;
try
{
    alternatePreviewImage.SetSource(fs);
    exceptionHappened = false;
}
finally
{
    if ( exceptionHappened )
    {    
        requiresSpecialPreview = false;
        etc;
    }
} 

      

-1


source







All Articles