Исключения действительно являются хорошим способом обработки ошибок из более низких уровней.
На мой взгляд, делегаты наиболее полезны, когда один объект, которому принадлежит другой объект, должен настроить этот объект. Это может иметь смысл, если ваши уровни логически «владеют» объектами на более низких уровнях, иначе я бы, вероятно, уклонился от шаблона делегата и использовал бы события.