Это будет работать полностью рекурсивно, если только крайнее исключение не решит переопределить ToString () без вызова базовой версии. Затем, конечно, метод возвращает то, что решит вернуть переопределенная версия. Поэтому разработчикам не рекомендуется переопределять ToString в своих собственных исключениях, чтобы сохранять поведение вызова ToString () для предсказуемого исключения.
Кстати, не имеет значение, если какое-либо из внутренних исключений переопределяет ToString (), потому что во время рекурсии открытый (виртуальный) метод ToString () не используется. Вместо этого вызывается закрытый метод ToString (bool), который выполняет всю работу и при необходимости вызывает себя для внутреннего исключения.