Все мои знания по этому вопросу взяты из этой статьи здесь: http://msdn.microsoft.com/en-us/magazine/cc793966.aspx - обратите внимание, что она написана для .NET 2.0, но у меня есть ощущение, что имеет смысл то, что мы испытывали в этом случае (подробнее чем "потому что решил" в любом случае)
Быстрый "У меня нет времени, чтобы прочитать эту статью" ответ (хотя вы должны, это действительно хороший):
Решение проблемы (если вам абсолютно НЕОБХОДИМО запустить ваши блоки finally) состоит в том, чтобы: а) включить глобальный обработчик ошибок или б) заставить .NET всегда запускать блоки окончательно и делать все так, как это делалось ( возможно, неправильный путь) в .NET 1.1 - поместите в свой app.config следующее:
<legacyUnhandledExceptionPolicy enabled="1">
Причина этого:
Когда исключение выдается в .NET, оно начинает проходить назад по стеку в поисках обработчиков исключений, а когда оно находит его, оно выполняет вторую прогулку по стеку, выполняя блоки finally с до выполнения содержимого перехвата , Если он не находит перехвата, этот второй обход никогда не происходит, поэтому блоки finally здесь никогда не запускаются, поэтому глобальный обработчик исключений всегда будет запускать предложения finally, так как CLR будет запускать их при обнаружении перехвата, а НЕ при запуске (что, как я верю, означает, что даже если вы сделаете улов / бросок, ваши блоки, в конце концов, все равно будут запущены).
Причина, по которой исправление app.config работает, заключается в том, что для .NET 1.0 и 1.1 в CLR был глобальный улов, который проглатывал бы исключения, прежде чем они стали неуправляемыми, что, конечно, было бы хитом, вызывая запуск блоков finally , Конечно, фреймворк не может знать достаточно об указанном Exception, чтобы справиться с ним, например, переполнение стека, так что это, вероятно, неправильный способ сделать это.
Следующий бит - то, где это становится немного липким, и я делаю предположения, основанные на том, что здесь говорится в статье.
Если вы находитесь в .NET 2.0+ без устаревшей обработки исключений, то ваше Исключение выпадет в систему обработки исключений Windows (SEH), которая кажется чертовски похожей на CLR, в которой она проходит через кадры до он не может найти перехват, а затем вызывает серию событий, называемых фильтром необработанных исключений (UEF). Это событие, на которое вы можете подписаться, но на него одновременно может быть подписана только ОДНА вещь, поэтому, когда что-то подписывается, Windows передает ему адрес обратного вызова, который был там раньше, что позволяет вам установить цепочку UEF обработчики - НО ОНИ НЕ ДОЛЖНЫ ХОЛОДИТЬ этот адрес, они должны сами назвать этот адрес, но если кто-то разорвет цепочку, бэп, вы больше не будете обрабатывать ошибки. Я предполагаю, что это то, что происходит, когда вы отменяете отчеты об ошибках Windows, это разрывает цепочку UEF, что означает, что приложение закрывается немедленно, а блоки finally не запускаются, однако, если вы позволите ему работать до конца и закроете его, это вызовет следующий UEF в цепочке. .NET зарегистрирует одно, из которого вызывается исключение AppDomain.UnhandledException (таким образом, даже это событие не гарантировано), которое, как я полагаю, также является местом, откуда вы вызываете свои блоки finally, поскольку я не могу понять, как, если вы никогда не переходите обратно в CLR может выполняться управляемый блок finally (статья не затрагивает этот бит.)