Некоторая справочная информация
Я программирую в системе, в которой используется собственный язык программирования, с возможностью использования специально приписанных классов .Net в проприетарном коде.
К сожалению, система не справляется с необработанными исключениями, всплывающими из кода .Net, если не факт; система падает без объяснения причин. Это раздражает, потому что мы часто хотим обрабатывать исключения в проприетарной системе , а не в коде .Net. Решение, предлагаемое поставщиком системы, состоит в том, чтобы упаковать исключение в специальный объект, который система обрабатывает .
Наш код .Net написан в виде шаблона фасада, и проблема заключается в том, что для обеспечения обработки каждого исключения, которое всплывает из кода .Net, каждый метод в фасаде должен включать блок try / catch, который переупаковывает любые исключения, которые могут возникнуть.
Вопрос
Я прочитал здесь множество тем, описывающих похожие сценарии, большинство из которых связаны с WinForms или сетью. Поскольку наш код не является ни тем, ни другим, вопрос заключается в том, существует ли какой-либо способ перехвата всех исключений в классе, чтобы мы могли его упаковать и перебросить их модифицированную версию?
Очевидно, что интерфейс между .Net-библиотеками, содержащими классы, и проприетарным языком полностью вне нашего контроля.
Редактировать
Я попробовал метод currentDomain.UnhandledException
, предложенный @VMAtm, к сожалению, безрезультатно. Обработчик событий не сработал, и родительская система получила исключение, а затем вела себя неправильно. Это снова привело меня в Google, и я нашел этот абзац здесь :
Первое, что нужно понять, это то, что событие UnhandledException не является обработчиком необработанного исключения. Регистрация на событие, вопреки тому, что сказано в документации :-(, не приводит к обработке необработанных исключений. (С тех пор они не будут обрабатываться, но я остановлюсь уже на циклическом рассуждении ...) Исключение UnhandledException событие просто уведомляет вас о том, что исключение прошло необработанным, если вы хотите попытаться сохранить состояние до того, как ваш поток или приложение умрет.
Jonathan Keljo, CLR Исключения PM
Это было слишком плохо, мне понравилась идея иметь "глобальный" блок try / catch. Я предполагаю, что это означает, что мне не удалось скрыть исключение от родительской системы. Поскольку я не знаю в первую очередь о том, как это реализовано в этой системе (и, честно говоря, я не знаю, в первую очередь, о том, как я сам продолжу это реализовывать), я нахожусь на очень слабом предположения, так что если кто-то может исправить меня, пожалуйста, продолжайте!
Ооо, ошибка, которую я получаю в родительской системе, - Exception has been thrown by the target of an invocation.
, насколько мне известно, сообщение из внешнего исключения .Net происходит. Если можно почитать что-нибудь из этого, я не знаю.
Я также попробую использовать Castle Dynamic Proxy, предложенный @jlew, но он выглядел намного сложнее, чем две строки AppDomain, и немного напугал меня:)
Решение
Если у вас та же проблема, что и у меня, вы должны сначала попробовать метод currentDomain.UnhandledException
, предложенный @VMAtm, потому что из-за того, что моя родительская система была особенно анальной, она не сработала.
Я получил его с помощью настройки Castle DynamicProxy. Это было действительно очень легко настроить. Моим тестовым примером был класс façade, инкапсулирующий класс XmlAttribute. Первое, что мне нужно было сделать, это написать прокси-класс:
public class AttribInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch (Exception e)
{
// Custom exception repackaging here
}
}
}
Тогда мне пришлось дать указание объекту фасада на самом деле использовать прокси. Я сохранил свое старое поле бэкэнда, но добавил следующее в c'tor:
public class CapXmlAttribute : CapPmlNetObject
{
private XmlAttributeBackend _xmlAttribute;
public CapXmlAttribute()
{
var generator = new ProxyGenerator();
_xmlAttribute = (XmlAttributeBackend) generator.CreateClassProxy(
typeof (XmlAttributeBackend), new AttribInterceptor());
}
}
Последним шагом была установка всех методов в бэкэнде, которые выставлены на фасад, как virtual
. Для меня это не было проблемой, но для других это может быть договор.
DynamicProxy действительно не так хорошо задокументировано, но я многому научился из учебника Кшиштофа Кочича и проекта кода Гамильтона Вериссимо .