Сперва не поверил ряду высказываний (про первые листинги). Потом проверил Ваши примеры. Посмотрел результат компиляции ILDasm'ом. Чуть не заплакал, когда увидел Activator.CreateInstance().
Немного расстроился оборачиванию исключений в TargetInvocationException и TypeInitializationException, но после просмотра IL и объяснений из статьи, понимаю, почему так. Но всё равно, грустно это всё. Жаль, что местами C# не следует принципу наименьшего удивления.
catch (AggregateException e)
{
ExceptionDispatchInfo di = ExceptionDispatchInfo.Capture(e.InnerException);
di.Throw();
return default(T);
}
Увидел такой код до того как прочитал статью, и внутри что-то ёкнуло :) Как мне кажется, вместо return default(T); лучше написать throw;
Хотя код не выполняется, но с throw как-то привычнее выглядит.
Есть правда одна неточность здесь: Особенность платформы .NET заключается в том, что в ней не существует (а точнее, как мы вскоре увидим – не существовало) способа перехвата исключения в одном месте и последующего его генерирования в другом.
На самом деле он в некотором роде существует. Взять тот же ThreadAbortException, который на первый взгляд не перехватывается catch. На самом деле он перехватывается, и снова генерируется в конце блока catch. И может быть погашен только с помощью Thread.ResetAbort().
Что интересно, так это то, что делается это не на уровне CIL, а как-то иначе.
Повторная генерация исключений