Используя события, а не исключения для реализации обработки ошибок

10
задан Jeremy McGee 29 September 2008 в 14:22
поделиться

9 ответов

Смотрите на это сообщение Udi Dahan. Изящный подход для диспетчеризации доменных событий. Предыдущий плакат корректен в высказывании, что Вы не должны использовать механизм события для восстановления с фатальных ошибок, но это - очень полезный шаблон для уведомления в слабо связанных системах:

public class DomainEventStorage<ActionType>
{
    public List<ActionType> Actions
    {
        get
        {
            var k = string.Format("Domain.Event.DomainEvent.{0}.{1}",
                                  GetType().Name,
                                  GetType().GetGenericArguments()[0]);
            if (Local.Data[k] == null)
                Local.Data[k] = new List<ActionType>();

            return (List<ActionType>) Local.Data[k];
        }
    }

    public IDisposable Register(ActionType callback)
    {
        Actions.Add(callback);
        return new DomainEventRegistrationRemover(() => Actions.Remove(callback)
            );
    }
}

public class DomainEvent<T1> : IDomainEvent where T1 : class
{
    private readonly DomainEventStorage<Action<T1>> _impl = new DomainEventStorage<Action<T1>>();

    internal List<Action<T1>> Actions { get { return _impl.Actions; } }

    public IDisposable Register(Action<T1> callback)
    {
        return _impl.Register(callback);
    }

    public void Raise(T1 args)
    {
        foreach (var action in Actions)
        {
            action.Invoke(args);
        }
    }
}

И использовать:

var fail = false;
using(var ev = DomainErrors.SomethingHappened.Register(c => fail = true) 
{
   //Do something with your domain here
}
3
ответ дан 3 December 2019 в 16:11
поделиться

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

Другой образ мыслей об этом: предположите, что метод предназначен для возвращения значения, но Вы обнаружили ошибку рано. Какое значение Вы возвращаете? Исключения передают то, что нет никакого соответствующего значения для возврата...

8
ответ дан 3 December 2019 в 16:11
поделиться

Это выглядит действительно нечетным мне, во-первых IDisposable является Вашим другом, используйте его.

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

Таким образом, это должно быть

using(var resource = AllocateLotsOfMemory())
{
   if(something_bad_happened) 
   {
     throw new SomeThingBadException();
   }
}
4
ответ дан 3 December 2019 в 16:11
поделиться

Если Вы думаете с точки зрения "Ошибок" и "Предупреждений", у меня была большая удача при резервировании событий для категории "Warning" и Исключений для категории "Errors".

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

Относительно Вашего Большого Объектного вопроса: Вы определенно не раздающие большие объекты, но это не означает, что Вы не можете передать ссылки на большие объекты вокруг. Существует много питания в способности сделать это.

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

4
ответ дан 3 December 2019 в 16:11
поделиться

1) это необходимо? никакой шаблон не абсолютно необходим

2) Windows Workflow Foundation делает это со всеми результатами Экземпляров Рабочего процесса, работающих в размещенном времени выполнения. Просто помните, что исключения могут произойти при попытке сгенерировать то событие, и Вы могли бы хотеть сделать свой код очистки Расположения или наконец блок в зависимости от ситуации, чтобы гарантировать, что это работает.

3
ответ дан 3 December 2019 в 16:11
поделиться

Честно говоря, события сигнальные ошибки кажутся мне страшный.

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

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

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

3
ответ дан 3 December 2019 в 16:11
поделиться

Другой основной проблемой с этим подходом являются проблемы параллелизма.

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

0
ответ дан 3 December 2019 в 16:11
поделиться

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

Также между Вашими двумя отрывками существует значительная разница.

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

Эмпирическое правило - то, что Исключения должны только быть выданы в невосстанавливаемых ситуациях. Мне действительно жаль, что C# не поддерживал пункт Бросков, это - единственная вещь, которую я действительно пропускаю от Java.

0
ответ дан 3 December 2019 в 16:11
поделиться

Первый фрагмент, вероятно, должен быть

resource = AllocateLotsOfMemory();
if (SomeCondition())
{
    try
    {
        OnOddError(new OddErrorEventArgs(resource.StatusProperty));
        return;
    }
    finally
    {
        resource.FreeLotsOfMemory();
    }
}

, иначе вы не освободитесь ваши ресурсы, когда обработчик событий генерирует исключение.

Как сказал Майк Браун, второй фрагмент также имеет проблему, если resource.FreeLotsOfMemory () не соответствует содержимому resource.StatusProperty ] вместо установки значения null .

1
ответ дан 3 December 2019 в 16:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: