Как реализации интерфейса должны обрабатывать неожиданные внутренние исключения типов, которые могут ожидать вызывающие?

2

Если класс реализует интерфейс, как он должен обрабатывать ситуации, когда либо

  1. При выполнении метода или свойства возникает внутренняя ошибка, которая имеет тип, который вызывающий может разумно ожидать но который, возможно, не должен. Например, IDictionary.Add делает что-то внутренне, что дает исключение ArgumentException при обстоятельствах, которые означают, что словарь поврежден, но не будет означать ничего плохого в остальной части системы? Или они подразумевают, что что-то повреждено за пределами словаря? Вызывающий может ожидать, что поймать и обработать тот факт, что в словаре существует дублирующийся ключ, поскольку в некоторых случаях исключение может быть Vexing (например, один и тот же код может использоваться для словаря, который не был доступен другим потокам и для ConcurrentDictionary который есть, и семантика будет работоспособна, если попытка добавить дублируемую запись вызовет чистый сбой). Предоставление прокрутки ArgumentException приведет к тому, что вызывающий агент полагает, что словарь находится в том же состоянии, что и добавление никогда не происходило, что может быть опасно, но бросание какого-либо другого типа исключений может показаться запутанным.
  2. При выполнении метода или свойства возникает исключение, которое, возможно, должно или не должно обрабатывать вызывающий объект, а определение интерфейса не дает никакого намека на то, что может возникнуть любое исключение, связанное с удаленностью. Например, предположим, что что-то пошло не так в оценке IEnumerator, либо подразумевая (1), что перечислитель получил повреждение (возможно, неожиданным действием в другом потоке), но повторное перечисление может преуспеть; (2) сам перечислимый объект, вероятно, поврежден или непригоден для использования, но все остальное в системе, вероятно, хорошо (например, лениво оцениваемая процедура разбора файла попадает в недопустимую запись); (3) что-то вне перечислимого объекта было повреждено. IEnumerable имеет только одно определенное исключение, которое может вызывать, но вызывающий может захотеть изменить свое действие на основе "серьезности" исключения. Если бы у меня были мои барабанщики, система определяла бы такие типы, как RetryableFailureException, CleanFailureException, ObjectCorruptFailureException, и большинству интерфейсов было бы позволено бросить их или их производные. Так как это не так, как правильно обрабатывать интерфейсы либо из вида интерфейса, либо из вызывающего?

    BTW, один шаблон, который я не видел, реализовал, но, казалось бы, был бы полезен, было бы для методов принимать параметр делегата, который должен выполняться, в случае, если метод завершился неудачно, что приведет к тому, что метод "try" вернет false, Такой делегат, предоставленный вызывающим, мог тогда не только генерировать исключение, которое должен знать получатель, но также может установить флаг, который в противном случае был доступен только вызывающему. Таким образом, вызывающий может знать, что исключение, которое было поймано, действительно было ожидаемым.

Теги:
exception
interface

1 ответ

0

Задача интерфейса заключается в определении членов (и их подписи), которые должен иметь класс, а не как их реализовать. Поэтому я бы сказал, пусть исключение пузырится вверх по стеку. Если вы действительно хотите определить контракт и контролировать некоторую реализацию (например, обработку ошибок), тогда вы должны сделать базовый класс (в этой ситуации я бы склонялся к классу MustInherit/Abstract) с помощью методов MustOverride, которые вызвал базовый класс из его методы (в вашей ситуации в Try Catch, чтобы вы могли выполнять специальную обработку ошибок).

  • 1
    Интерфейс не определяет, как члены должны быть реализованы, но на практике, интерфейсы должны быть связаны с поведением, описанным в их документации. Если что-то реализует IList <Integer>, оно должно вести себя как адресуемая коллекция. Вызов Add (5) должен поместить другой элемент в коллекцию со значением 5; например, он не должен увеличивать значение всех элементов в коллекции на 5. Казалось бы, исключения, которые могут вызываться интерфейсным методом, должны рассматриваться как часть его поведения.
  • 1
    Я думаю, что @NoAlias пытается сказать: интерфейс - это способ определить требуемую структуру объекта, а базовый класс - это то, как вы будете кодировать эти требования. Таким образом, вы называете функцию в интерфейсе, а затем кодируете ее основные или обязательные процессы в базовом классе. Да, вы можете иметь структуру «error» в интерфейсе, но фактическая обработка ошибок и заполнение структуры должны быть закодированы в базовом классе.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню