Nano Hash - криптовалюты, майнинг, программирование

Используете общий класс для выполнения с помощью try / catch / finally?

Я обнаружил, что у меня много этого в разных методах в моем коде:

try
{
  runABunchOfMethods();
}
catch (Exception ex)
{
  logger.Log(ex);
}

А как насчет создания этого:

public static class Executor
{

    private static ILogger logger;

    public delegate void ExecuteThis();

    static Executor()
    {
        // logger = ...GetLoggerFromIoC();
    }

    public static void Execute<T>(ExecuteThis executeThis)
        where T : Exception
    {
        try
        {
            executeThis();
        }
        catch (T ex)
        {
            // Some kind of Exception Handling Strategy...
            logger.Log(ex);
            // throw;
        }
    }

}

И просто используя это так:

private void RunSomething()
{
  Method1(someClassVar);
  Method2(someOtherClassVar);
}

...

Executor.Execute<ApplicationException>(RunSomething);

Есть ли у такого подхода минусы? (Вы можете добавить Executor-методы и делегаты, когда хотите, наконец, и использовать дженерики для типа Exeception, который вы хотите поймать ...)

Изменить: извините за непонятность - то, что мне действительно нужно, было некоторым вкладом в общую идею попытки перенести выполнение кода из рассматриваемого класса в более общий класс, который делает это. Я только что сделал быстрый макет решения, но в реальной жизни вы, естественно, использовали бы такие вещи, как стратегии обработки исключений, абстрактные базовые классы выполнения с более специализированными классами выполнения для определенного уровня / части системы. Обычно я создаю один метод с частью try ... / runABunchOfMethods (это обработка исключений со специализированными исключениями), который вызывает runABunchOfMethods, который, в свою очередь, выполняет ограниченный набор других методов в стиле «чистого кода».

Я куплю аргумент обфускации на некоторых уровнях, но если все решение / архитектура будет придерживаться этого предложенного подхода, новый программист должен быть в состоянии понять шаблон.

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


Ответы:


1

Если вы хотите, чтобы ваши объекты были чистыми, вы можете рассмотреть возможность использования инфраструктуры АОП, например PostSharp. . Тогда ваш журнал исключений (например) может быть обработан в одном месте, если вы того пожелаете.

РЕДАКТИРОВАТЬ:

Можно удалить блоки try / catch с помощью postharp - вот пример общего обработчика исключений, который можно создать в PostSharp:

[Serializable]
public class CommonExceptionHandling : OnExceptionAspect
{
    public override void OnException(MethodExecutionEventArgs eventArgs)
    {
        // can do some logging here
        // ...

        // throw the exception (out of postsharp) to where it occurred:
        eventArgs.FlowBehavior = FlowBehavior.RethrowException;                       

        // If you want to ignore the exception, you can do this:
        //eventArgs.FlowBehavior = FlowBehavior.Return;

        base.OnException(eventArgs);
    }
}

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

11.06.2010
  • Хороший! Это было именно то, что я искал - и использование атрибутов в ваших методах намного лучше, чем Executer.Execute (делегат) -stuff. Похоже, я был не так уж далек от ответа, как все думали ... :) Кто-нибудь знает какие-либо другие фреймворки АОП, которые поддерживают обработку исключений в стиле АОП? (Для сравнения...) 11.06.2010
  • Или вместо PostSharp используйте структуру внедрения зависимостей, большая часть которой позволяет динамический перехват вызовов методов. 15.08.2013

  • 2

    Обратной стороной является ваш подход к общей обработке исключений. Вы не должны ловить базовый класс Exception без веской причины. Он мог скрывать различные проблемы; хорошо, вы регистрируете их, но ваш код не знает, что он только что запустил нехватку памяти или файл не существует, и продолжайте, как если бы не было проблем в all.
    Метод, который вы здесь описываете, поощряет общую обработку исключений.

    По теме:
    Неужели так плохо поймать общее исключение?
    Это плохая практика для перехвата неспецифического исключения, такого как System.Exception? Почему?

    ИЗМЕНИТЬ (ответ на изменение и пояснение OP):
    Я не уверен, чего вы хотите достичь. В основном вы скрываете исключение (общее или конкретное - оно просто проглатывается). Назовите свой метод Executor.Hide<ApplicationException>( RunSomething ); и станет понятно, что здесь происходит. Но есть ли преимущество в проглатывании исключений? Я так не думаю. Опять же, могут быть места, где вам это нужно, но они редки и должны быть выбраны намеренно. Предоставляемый вами метод побуждает проглатывать исключение, не задумываясь об этом.
    Вы закомментировали строку повторного вызова (throw ex или лучше просто throw, которая сохраняет стек). Что вы получаете, если эта линия включена? В основном просто логирование. Вы перехватываете исключение, регистрируете его и повторно генерируете, чтобы ... поймать его снова? Почему вы не можете поместить журнал в это последнее место?
    Старайтесь перехватывать исключение только тогда, когда вы можете его обработать. Там вы тоже можете войти. Любой хороший регистратор сможет показать вам трассировку стека, так что вы не потеряете информацию.

    По теме:
    Где поставить try catch?

    11.06.2010
  • Я отредактировал код, чтобы использовать дженерики и передать исключение T :, чтобы показать, что вы можете легко указать специализированное исключение. Пожалуйста, посмотрите мою правку. 11.06.2010
  • Почему вы не можете поместить журнал в это последнее место? - Я обычно использую разные стратегии ведения журнала, вводимые через IoC, в зависимости от уровня в области видимости (большинство ошибок регистрируются в базе данных, но что, если сервер базы данных не работает? - тогда я регистрируюсь на SMTP - т.е. отправляю письмо). Уровень должен иметь возможность обрабатывать некоторые типы исключений, не передавая их в пользовательский интерфейс. 11.06.2010

  • 3

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

    11.06.2010
  • Я не уверен, код с кучей встроенной обработки исключений не так-то легко читать. И в данном случае это довольно интуитивный паттерн. 11.06.2010

  • 4

    Обратной стороной будет отсутствие гибкости. Что делать, если вы хотите восстановиться после определенного исключения в одном из вызываемых методов - например, при неудачном подключении к SMTP-серверу вы можете захотеть сохранить содержимое исходящей почты в своей базе данных, чтобы повторить попытку позже? Это причина, по которой вам следует по возможности избегать перехвата общего типа исключения.

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

    11.06.2010

    5

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

    Я понятия не имею, какое приложение вы пишете, но разве вы не можете перехватить такие события, как AppDomain.UnhandledException, который срабатывает всякий раз, когда в каком-либо потоке есть необработанное исключение (которое вы не поймали), и регистрировать их? Возможно, вы захотите объединить это с более конкретными операторами catch, которые также регистрируют, если вы также хотите регистрировать восстанавливаемые исключения.

    11.06.2010
  • Ага, Exception ex был просто иллюстрацией (хотя и плохой). Мы говорим о методах на очень низком уровне, где ограниченное количество исключений находится в области действия. 11.06.2010

  • 6

    На самом деле вы ничего не выигрываете, но кое-что теряете:

    • Читаемость
    • Простота (вы вводите другой класс, еще один делегат, который читатель должен понимать)
    • Вы не можете просто перешагнуть через Executor.Execute, чтобы перейти к Method1 (...). Если вы перейдете, вы пропустите весь блок кода в своем делегате.
    • ...
    11.06.2010
  • +1 за точку отладки - это действительно серьезная проблема! Спасибо! 11.06.2010

  • 7

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

    • В консольном приложении вы должны перехватывать и регистрировать исключения в Main.
    • В приложении WinForms вы должны перехватывать и регистрировать исключения в ваших обработчиках событий.
    • В службе вы должны перехватывать и регистрировать исключения, а затем ThreadProcs ваших рабочих потоков.
    • И Т. Д.

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

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

    11.06.2010
  • Ага, я отредактировал вопрос, чтобы попытаться лучше объяснить свои намерения. Меня беспокоит то, что я хочу, чтобы мои настоящие объекты были как можно более чистыми. В моем примере я использовал ведение журнала в качестве примеров, но я также думаю о различных аспектах (таких как аудит, трассировка и т. Д.), Которые я бы предпочел не загромождать свой обычный код. Я считаю, что большая часть паттерна такая же, поэтому я хотел бы повторно использовать его в более общем виде, но с учетом специализации. 11.06.2010
  • @antirysm: Мартин считает, что вы можете сохранить свои реальные объекты чистыми от операторов try / catch, не помещая в них операторы try / catch вообще. Позвольте им подняться в верхнюю часть вашего приложения и регистрировать их там. 15.08.2013

  • 8

    Я перейду на подножку «это заставляет вас злоупотреблять исключениями, вылавливая только на общем уровне». Однако в более специализированных случаях вам может пригодиться некоторая «оболочка делегата обработки исключений». Например, если вы много работали с классами, связанными с БД, которые всегда генерируют одни и те же исключения, у вас может быть выделенная оболочка-исключение БД.

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

    11.06.2010
  • +1 Спасибо за понимание смысла моего вопроса! :) Пожалуйста, посмотрите мою правку! 11.06.2010

  • 9

    В самом начале ....

    У вас НЕ должно быть кода, подобного приведенному ниже, разбросанного по вашей базе кода.

    try 
    { 
      runABunchOfMethods(); 
    } 
    catch (Exception ex) 
    { 
      logger.Log(ex); 
    } 
    

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

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

    11.06.2010
  • Я должен был быть более ясным; приведенный выше код будет единственным кодом в функции; runABunchOfMethods () будет содержать вызовы ограниченного набора других функций. Чистый код / ​​в стиле дяди Боба ... 11.06.2010
  • Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..