Итак, в .NET то, что вы просите, теоретически возможно, но это будет непросто.
CIL фактически определяет пять типов блоков обработки исключений! try
, catch
и finally
те, к которым вы привыкли в C #, и два других:
filter
- аналогично блоку catch
, но может запускать произвольный код, чтобы определить, хочет ли он обработать ошибку, а не просто сопоставить по типу. Этот блок имеет доступ к объекту исключения и оказывает такое же влияние на трассировку стека исключений, что и блок catch
.
fault
- аналогично блоку finally
, однако он запускается только при возникновении исключения. Этот блок не имеет доступа к объекту исключения и не влияет на трассировку стека исключений (как блок finally
).
filter
доступно на некоторых языках .NET (например, VB.NET, C ++ / CLI), но, к сожалению, недоступно в C #. Однако я не знаю ни одного языка, кроме CIL, который позволял бы выражать блок fault
.
Поскольку это можно сделать в IL, значит, не все потеряно. Теоретически вы можете использовать Reflection.Emit для динамического запуска функции с блоком fault
, а затем передать код, в котором вы хотите выполнить, в виде лямбда-выражений (т. Е. Один для части try, один для части fault и т. Д. ), однако (а) это не легко, и (б) я не уверен, что это действительно даст вам более полезную трассировку стека, чем вы получаете в настоящее время.
Извините, ответ не типа "вот как это сделать", но, по крайней мере, теперь вы знаете! То, что вы делаете сейчас, вероятно, лучший подход ИМХО.
Обратите внимание на тех, кто говорит, что подход, использованный в вопросе, является «плохой практикой», на самом деле это не так. Когда вы реализуете блок catch
, вы говорите: «Мне нужно что-то делать с объектом исключения, когда возникает исключение», а когда вы реализуете finally
, вы говорите: «Мне не нужен объект исключения, но Мне нужно что-то сделать до конца функции ".
Если вы на самом деле пытаетесь сказать: «Мне не нужен объект исключения, но мне нужно что-то делать, когда возникает исключение», тогда вы на полпути между ними, то есть вы хотите fault
блок. Так как это не доступно в C #, у вас нет идеального варианта, поэтому вы можете также выбрать вариант, который с меньшей вероятностью вызовет ошибки, забыв повторно выбросить, и который не повредит трассировку стека.