Подход к функции высокого порядка для исключений в C #

2

Привет всем, я думал о передаче блоков метода в качестве аргументов для вспомогательных классов, которые были созданы в обработке исключений, но это одна из тех вещей, которые интуитивно понятны, и я хотел бы представить ее для критики, понимания или совета.

Я хотел бы отметить, что это НЕ, как я выполняю всю обработку исключений, но есть случаи, когда я считаю эту структуру более "читаемой".

Например, у меня есть сценарий, в котором я показываю изображение предварительного просмотра, но если это не удается (это реальный сценарий, когда я просматриваю изображения, а некоторые форматы GIF/BMP не могут быть просмотрены), это просто сценарий, где я вместо предварительного просмотра отобразите альтернативное изображение. Блок кода try/catch выглядит следующим образом:

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

Итак, я использую вспомогательный класс, который принимает параметр метода, чтобы он выглядел следующим образом:

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

ErrorHelper.RunWithSuccessNotify довольно прост:

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

    return success;
}

Позвольте мне еще раз подчеркнуть, что это полезно для этих сценариев с низким уровнем воздействия, а также для других, где я могу подавить исключение:

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

Подход может быть более подробным, чтобы учесть исключение:

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

Итак, каковы мысли по этому набору тактики для централизации обработки исключений? Если это плохое направление, существуют ли конкретные причины, по которым это может привести к неприятностям?

Теги:
exception-handling

6 ответов

3

Основная проблема, с которой я столкнулся бы с этим подходом, - это ловить Exception, как правило, считается плохим. Если бы какой-то способ указать, какой тип исключения можно поймать, я могу его купить, но я считаю, что это нужно указывать во время компиляции. Я также не чувствовал бы себя полностью комфортно с улавливанием всех исключений и перестройкой тех, которые не совпадают.

Помните, что когда вы поймаете исключение, вы, по сути, говорите, что можете обработать ошибку каким-либо значимым образом. Очевидно, что код выше не может обрабатывать StackOverflowException или MissingMethodException.

  • 0
    Небольшая деталь: вы не можете поймать StackOverflowException в последних версиях фреймворка, если вы не бросили его самостоятельно.
  • 2
    У вас может быть общая версия, где вы указываете ожидаемое исключение
Показать ещё 1 комментарий
1

Не ловите все исключения, параметризуйте тот, который вы хотите:

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;
            }
        }
    }
}

Не очень похоже на С#, но может быть полезно в том же случае (когда вы хотите абстрагироваться от обработки исключения).

Вам нужно написать различную сигнатуру типа для каждого типа функции, потому что С# не поддерживает currying. Виниловая расточка.: D

Это не очень изящное решение, но оно дает вам подсказку о том, как все работает на функциональных языках. Очень интересно учиться.

0

Взгляните на ЭТО и, возможно, немного отбросьте рефлектор ol. Мне кажется, что то же самое делается там, но, возможно, более полным образом... Это кажется очень сильным...

0

Здравствуйте, я не знаю, хорошо ли он масштабируется, но на данный момент моя команда использует его в нашем измерительном программном обеспечении для обработки специального исключения (например, связи с каким-то устройством измерения) и перезапускает измерение в этом случае.

В настоящее время он работает хорошо, особенно в тех случаях, когда важная/не повторяющаяся часть кода находится в функции (параметр Action), вызываемой и не выполняющей обработку исключений.

Лучшим случаем является то, что они даже могут быть вложенными, а основной код доступен для чтения.

С другой стороны вы скрываете, что именно ваша обработка исключений делает за именем функции, поэтому она должна быть простой или понятной, чтобы быть понятной только по имени функции, иначе вы запутываете что-то от будущих читателей вашего кода (вы сами включили)

0

Моя первоначальная мысль просто заключается в том, что передача сложных анонимных делегатов вокруг плохо пахнет. Ничего не мешает кому-то сбросить анонимного делегата сложной логикой в ​​методы ErrorHelper. Такая логика становится трудной для тестирования. Я бы предпочел, чтобы логика передавалась только в объекте, который мне кажется более понятным методом. Для меня анонимные делегаты (и лямбды) предназначены для очень простой логической расширяемости, например, для логики сравнения. Механика анонимных делегатов является мощной и может быть использована для других целей, но с большой силой приходит большая ответственность. =)

То, что вы достигаете с помощью своей техники, - это способность чистого изменения стратегии обработки исключений во время выполнения. Но действительно ли это требование?

  • 1
    У лямбды гораздо больше пользы, чем у простой логики. Думай нестандартно.
  • 1
    Ах, спасибо за инструкцию. Мне никогда не приходило в голову думать из коробки. Я начну это делать. Хе-хе, конечно, у лямбд есть больше пользы. Означает ли это, что любое возможное системное разделение должно быть достигнуто с помощью лямбд? Ни за что. В большинстве случаев я бы сказал, что внедрение объектно-ориентированной зависимости все же лучше. Думайте за пределами коробки.
-2

Если я понял, что вы пытаетесь сделать, тогда мне кажется ужасным, как стандартный шаблон управления ошибками. Это предупреждающий знак прямо там, так как мне потребовалось некоторое время, чтобы понять вашу идею.

Если нет веской причины, код должен быть явно доступен в методе для любого разработчика технического обслуживания для просмотра и изменения, а не для передачи из других мест. Просто потому, что существует функция, не означает, что она полезна в большинстве ситуаций. В этом случае я не вижу никакой пользы от обфускации.

Кстати, я думаю, что вы прибиваете труп к стене, перехватывая System.Exception. Нормальное правило заключается не в том, чтобы исключить исключение, если вы не знаете, что такое исключение, и/или вам нужно знать детали исключения по какой-либо причине.

Обычно используемый шаблон для восстановления в случае неизвестного исключения выглядит примерно так:

bool exceptionHappened = true;
try
{
    alternatePreviewImage.SetSource(fs);
    exceptionHappened = false;
}
finally
{
    if ( exceptionHappened )
    {    
        requiresSpecialPreview = false;
        etc;
    }
} 
  • 0
    Чем такой наконец {if (expcetionHappened) {..}} отличается от перехвата Exception? Можно ли бросить что-то, что не происходит из исключения?
  • 0
    Проблема с перехватом исключения, когда вам не нужно этого делать, заключается в том, что вам нужно либо проглотить исключение (обычно не очень хорошее), либо вам нужно его повторно выбросить. Catch-rethrow нарушает механизм двойного прохода исключения и, следовательно, дает жалкий опыт отладки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню