Как определить, обрабатывается ли исключение.NET?

Узел может быть многими различными видами вещей: некоторый текст, комментарий, элемент, объект, и т.д. Элемент является конкретным видом узла.

15
задан John Saunders 25 March 2010 в 19:10
поделиться

5 ответов

http://www.codewrecks.com/blog/index.php/2008/07/25/detecting-if-finally-block-is-executing-for-an-manhandled- exception / описывает «взлом», чтобы определить, выполняется ли ваш код в режиме обработки исключений или нет. Он использует Marshal.GetExceptionPointers , чтобы узнать, является ли исключение «активным».

Но имейте в виду:

Замечания

GetExceptionPointers предоставляется компилятором только для поддержки структурированной обработки исключений (SEH). NoteNote:

Этот метод использует SecurityAction.LinkDemand для предотвращения его вызова из ненадежного кода; только непосредственный вызывающий должен иметь разрешение SecurityPermissionAttribute.UnmanagedCode. Если ваш код может быть вызван из частично доверенного кода, не передавайте вводимые пользователем данные в методы класса Marshal без проверки. О важных ограничениях на использование члена LinkDemand см. В разделе «Спрос против запроса».

12
ответ дан 1 December 2019 в 02:37
поделиться

Это не такая уж плохая идея; он просто не кажется идеальным в C # /. NET .

В C ++ есть функция, которая позволяет коду определять, вызывается ли он из-за исключения. Это наиболее важно в деструкторах RAII; Деструктор может выбрать фиксацию или прерывание в зависимости от того, является ли поток управления нормальным или исключительным. Я думаю, что это довольно естественный подход, но отсутствие встроенной поддержки (и морально сомнительная природа обходного пути; мне кажется, что это скорее зависит от реализации), вероятно, означает, что следует использовать более традиционный подход.

2
ответ дан 1 December 2019 в 02:37
поделиться

Оператор using - это просто синтаксический сахар для блока try finally. Вы можете получить то, что хотите, напечатав, наконец, попытку полностью, а затем добавив оператор catch для обработки вашего особого случая:

try
{
    IDisposable x = new MyThing();
}
catch (Exception exception) // Use a more specific exception if possible.
{
    x.ErrorOccurred = true; // You could even pass a reference to the exception if you wish.
    throw;
}
finally
{
    x.Dispose();
}

Внутри MyThing вы можете сделать это, если хотите, например:

class MyThing : IDisposable
{
    public bool ErrorOccurred() { get; set; }

    public void Dispose()
    {
        if (ErrorOccurred) {
            RollBack();
        } else {
            Commit();
        }
    }
}

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

Вот лучший способ сделать что ты хочешь:

using (IDisposable x = new MyThing())
{
    x.Foo();
    x.Bar();
    x.CommitChanges();
}

class MyThing : IDisposable
{
    public bool IsCommitted { get; private set; }

    public void CommitChanges()
    {
        // Do stuff needed to commit.
        IsCommitted = true;
    }

    public void Dispose()
    {
        if (!IsCommitted)
            RollBack();
    }
}
2
ответ дан 1 December 2019 в 02:37
поделиться

Эта информация вам недоступна.

Я бы использовал шаблон, аналогичный тому, который используется классом DbTransaction: то есть ваш класс IDisposable должен реализовывать метод, аналогичный DbTransaction. Зафиксировать (). Затем ваш метод Dispose может выполнять различную логику в зависимости от того, был ли вызван Commit (в случае DbTransaction, транзакция будет отменена, если она не была зафиксирована явно).

Пользователи вашего класса затем будут использовать следующие шаблон, похожий на типичный DbTransaction:

using(MyDisposableClass instance = ...)
{
    ... do whatever ...

    instance.Commit();
} // Dispose logic depends on whether or not Commit was called.

EDIT Я вижу, вы изменили свой вопрос, чтобы показать, что вы знаете об этом шаблоне (в вашем примере используется TransactionScope). Тем не менее я думаю, что это единственно реальное решение.

4
ответ дан 1 December 2019 в 02:37
поделиться

Не ответ на вопрос, а просто примечание о том, что я так и не воспользовался «принятым» хаком в реальном коде, поэтому он по большей части не протестирован » в дикой природе ». Вместо этого мы выбрали что-то вроде этого:

DoThings(x =>
{
    x.DoSomething();
    x.DoMoreThings();
});

где

public void DoThings(Action<MyObject> action)
{
    bool success = false;
    try
    {
        action(new MyObject());
        Commit();
        success = true;
    }
    finally
    {
        if (!success)
            Rollback();
    }
}

Ключевым моментом является то, что он такой же компактный, как пример «использования» в вопросе, и не использует никаких хаков.

Среди недостатков - снижение производительности (совершенно незначительное в нашем случае) и переход F10 в DoThings , когда я действительно хочу, чтобы он просто переходил прямо к x.DoSomething () . Оба очень второстепенные.

7
ответ дан 1 December 2019 в 02:37
поделиться
Другие вопросы по тегам:

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