c# “наконец” блокируются, который только работает на исключениях

Полагаю, у вас есть поле id.

delete from customer 
where id not in (
    select min(id)
    from customer
    group by email, first_name, last_name
)

Подзапрос находит идентификатор строк, которые вы хотите сохранить. Затем вы удаляете другие строки

7
задан 19 revs, 4 users 80% 13 January 2011 в 15:05
поделиться

14 ответов

Так, в.NET, что Вы просите, теоретически возможно, но это не будет легким.

CIL на самом деле определяет пять типов блока обработки исключений! try, catch и finally Вы привыкли к в C# и двух других:

  • filter - подобный a catch блок, но может выполнить произвольный код, чтобы определить, хочет ли он обработать ошибку, вместо того, чтобы просто соответствовать на типе. Этот блок имеет доступ к объекту исключения и имеет тот же эффект на отслеживание стека исключительной ситуации как a catch блок.

  • fault - подобный a finally блок, однако это только выполняется, когда исключение происходит. Этот блок не имеет доступа к объекту исключения и не имеет никакого эффекта на отслеживание стека исключительной ситуации (точно так же, как a finally блок).

filter доступно на некоторых языках.NET (например, VB.NET, C++ / CLI), но не доступен в C#, к сожалению. Однако я не знаю ни о каком языке кроме CIL, который позволяет fault блок, который будет выражен.

Поскольку это может быть сделано в средствах IL не, все потеряно, все же. В теории Вы могли использовать Отражение. Испустите для динамичного испускания функции, которая имеет a fault блок и затем передает код, в котором Вы хотите работать как лямбда-выражения (т.е. один для части попытки, один для части отказа, и так далее), однако (a) это не легко и (b) я не убежден, что это на самом деле даст Вам более полезное отслеживание стека, чем Вы в настоящее время добираетесь.

Извините ответ не, "вот то, как сделать, он" вводит вещь, но по крайней мере теперь Вы знаете! Что Вы делаете, теперь, вероятно, лучший подход, по моему скромному мнению.


Отметьте тем, которые говорят, что подход, используемый в вопросе, является 'плохой практикой', это действительно не. Когда Вы реализуете a catch блок Вы говорите, "Что я должен сделать что-то с объектом исключения, когда исключение происходит" и когда Вы реализуете a finally Вы говорите, что "Мне не нужен объект исключения, но я должен сделать что-то до конца функции".

Если то, что Вы на самом деле пытаетесь сказать, "Мне не нужен объект исключения, но я должен сделать что-то, когда исключение происходит", затем Вы - половина пути между этими двумя, т.е. Вы хотите a fault блок. Поскольку это не доступно в C#, у Вас нет идеальной опции, таким образом, можно также выбрать опцию, которая, менее вероятно, вызовет ошибки, забывая повторно бросать, и которая не повреждает отслеживание стека.

34
ответ дан 6 December 2019 в 04:44
поделиться
try
{
   MightThrow();
}
catch
{
   DoSomethingOnFailure();
}
-1
ответ дан 6 December 2019 в 04:44
поделиться

Нет, я думаю, что это - общая идиома путем, у Вас есть она.

РЕДАКТИРОВАНИЕ, Чтобы быть ясной, "выгода" затем "повторно бросает" предложение стратегий та же семантика во время выполнения, однако они изменяют опыт, когда отладчик VS присоединяется. Инструменты и обслуживание важны; отладка часто требует, чтобы Вы 'поймали все исключения первого шанса и если Вы заканчиваете за большим количеством исключений первого шанса 'spuriou из-за catch-then-rethrow в Вашем коде, это действительно повреждает способность отладить код. Эта идиома о взаимодействии хорошо с инструментами, а также ясно выражением намерения (Вы не хотите 'ловить', решать, не может обработать, и перебросок, вместо этого Вы просто хотите зарегистрировать это, исключение действительно происходило, но позволяло ему перейти).

0
ответ дан 6 December 2019 в 04:44
поделиться

Не это то же как:

try 
{
    MightThrow();
}
catch (Exception e) 
{
    DoSomethingOnFailure();
    throw e;
}

?

1
ответ дан 6 December 2019 в 04:44
поделиться

Как насчет того, чтобы только ловить исключение, которое не выдает "MightThrow"?

Bool bad = true;
try
{
   MightThrow();
   bad = false;
}
catch (SomePrivateMadeUpException foo)
{ 
   //empty
}
finally
{
   if(bad) DoSomeLoggingOnFailure();   
}
2
ответ дан 6 December 2019 в 04:44
поделиться

Вы могли инкапсулировать свою логику в пользовательском классе, чем-то как:

    public  class Executor
{
    private readonly Action mainActionDelegate;
    private readonly Action onFaultDelegate;

    public Executor(Action mainAction, Action onFault)
    {
        mainActionDelegate = mainAction;
        onFaultDelegate = onFault;
    }

    public  void Run()
    {
        bool bad = true;
        try
        {
            mainActionDelegate();
            bad = false;
        }
        finally
        {
            if(bad)
            {
                onFaultDelegate();
            }
        }
    }

}

И используйте его как:

            new Executor(MightThrow, DoSomeLoggingOnFailure).Run();

Надеюсь, это поможет.

2
ответ дан 6 December 2019 в 04:44
поделиться

Позвольте мне резюмировать Ваши требования путем, я понимаю их:

  1. Вы хотите некоторый код, который выполняется только, когда исключение сгенерировано, чтобы сделать некоторый вход.
  2. Вы хотите выполнить свою среду тестирования под отладчиком и повреждением в точке, в которой выдается исключение.

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

Для соответствия второму требованию при использовании выгоды без параметров Вы могли настроить свой отладчик для повреждения, когда исключением является бросок, не только когда существует необработанное исключение. Я подозреваю, что Вы знаете, как сделать это, но я помещу его здесь для полноты ответа: в VS можно сделать это в Отладке-> Исключение->, Исключения Общеязыковой среды выполнения-> проверяют флажок Thrown.

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

Однако, ли наконец код выполняется, зависит от отладчика, который Вы используете. В частности, VS повредится на unhadled исключении, прежде чем наконец будет выполнен и не позволит Вам продолжить. Таким образом, если Вы не отсоединяетесь от процесса в той точке, Ваш код входа никогда не будет выполняться. Другими словами, второе требование вмешается в соответствие первому требованию.

2
ответ дан 6 December 2019 в 04:44
поделиться

"Наконец" блок, который работает только при отказе, называют "выгодой" (без параметров).:-)

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

Таким образом я сделал бы что-то как:

  try
  {
    MightThrow();
  }
  catch(MyException ex)
  {
    // Runs on MyException
    MySpecificFailureHandler()
    // Since we have handled the exception and can't execute the generic
    // "catch" block below, we need to explicitly run the generic failure handler
    MyGenericFailureHandler()
  }
  catch
  {
    // Runs on any exception hot handled specifically before
    MyGenericFailureHandler()
    // If you want to mimic "finally" behavior and propagate the exception
    // up the call stack
    throw;
  }
  finally
  {
    // Runs on any failure or success
    MyGenericCleanupHandler();
  }
3
ответ дан 6 December 2019 в 04:44
поделиться

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

try
{
   MightThrow();
}
catch
{
   DoSomthingOnFailure();
   throw;
}
4
ответ дан 6 December 2019 в 04:44
поделиться

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

try
{
   MightThrow();
}
catch (Exception ex)
{
   // this runs only when there was an exception
   DoSomthingOnFailure();
   // pass exception on to caller
   throw; 
}
finally
{
   // this runs everytime
   Cleanup();
}
7
ответ дан 6 December 2019 в 04:44
поделиться

Что случилось с:

try
{
   MightThrow();
}
catch
{
   DoSomthingOnFailure();
   throw;
}
7
ответ дан 6 December 2019 в 04:44
поделиться

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

Если Вы открываете, Tools|Exceptions затем отмечают поле Common Language Runtime Exceptions, отладчик остановится при исключении независимо от любых блоков попытки/выгоды/наконец.

Обновление: можно указать точное исключение, которое Вы хотите поймать путем расширения [+] дерево в диалоговом окне Исключений. Хотя, конечно, это будет стрелять каждый раз, когда любое исключение указанного типа [s] происходит [s], можно включить и выключить его по желанию даже посреди сеанса отладки, таким образом, с разумным использованием точек останова можно заставить это выполнять указания. Я использовал его успешно для двигений, 'цель вызова выдала исключение' боль шара, происходящая из использования отражения для инстанцирования объектов. Очень полезный инструмент при таких обстоятельствах. Также отметьте местных жителей, и отслеживание стека должно быть твердо доступным насколько я вспоминаю (просто сделал быстрый тест, и они доступны), таким образом, никакие проблемы там.

Конечно, если Вы хотите зарегистрировать вещи затем, это выходит за рамки отладчика IDE; и, в этом случае исключения первого шанса не помогут Вам!

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

11
ответ дан 6 December 2019 в 04:44
поделиться

Как насчет этого:

try
{
  MightThrow();
}
catch
{
  DoSomethingOnFailure();
  throw; // added based on new information in the original question
}

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

[Редактирование: Разъяснение]

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

[Второе редактирование: Относительно Вашего разъяснения]

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

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

[Заключительное редактирование: у Вас есть свой ответ]

kronoz глубокомысленно предоставил Вам ответ, который Вы искали. Не повреждайтесь лучшие практики - используют Visual Studio правильно! Можно установить Visual Studio для повреждения точно, когда исключение выдается. Вот официальная информация о предмете.

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

27
ответ дан 6 December 2019 в 04:44
поделиться

Каждый пример до сих пор теряет исходный StackTrace согласно моим тестам. Вот решение, которое должно работать на Вас.

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

try
{
   MightThrow();
}
catch (Exception ex)
{
    DoSomethingOnFailure();
    PreserveStackTrace(ex);
    throw;
}
2
ответ дан 6 December 2019 в 04:44
поделиться
Другие вопросы по тегам:

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