Пусть общий код принимает делегат, который будет вызываться при возникновении плохого состояния (возможно, функция, которая возвращает false). Тогда:
if (SomethingBadHappened)
return ReportSomethingBad(new ImNotFeelingWellException("I'm not feeling too well..."));
Версия подпрограммы "TryDoingSomething" (которая должна возвращать False, а не генерировать исключение) должна вызывать общую версию с делегатом, который ничего не делает, кроме как возвращает false. Версия «DoSomethingAndThrowExceptionIfItFails» должна вызывать общую процедуру с делегатом, который будет выдавать переданное исключение.
Выполнение таких действий позволит исключениям содержать гораздо больше полезной информации, чем было бы возможно, если бы они были просто сгенерированы подпрограммой TryDoingSomething (), которая вернула false.