Каков наилучший способ показать реализацию унаследованного интерфейса в C #?

2

Учитывая следующие интерфейсы:

interface IFoo
{
    void Foo();
}

interface IBar : IFoo
{
    void Bar();
}

Каков наилучший способ указать, что данный класс реализует IBar?

Подход A:

class Implementation : IBar { ... }

Это кажется более простым и чистым, но это не означает, что Implementation реализует IFoo.

Подход B:

class Implementation : IBar, IFoo { ... }

Это кажется наиболее информативным, но действительно ли необходима дополнительная информация?

Теги:
interface

7 ответов

5
Лучший ответ

Лично я бы пошел с первым. С последним, скажем, вы находитесь в такой ситуации, когда у вас есть куча производных классов:

class DerivedA : Implementation, IBar, IFoo { ... }
class DerivedB : Implementation, IBar, IFoo { ... }
class DerivedC : Implementation, IBar, IFoo { ... }
class DerivedD : Implementation, IBar, IFoo { ... }

И тогда ваши требования для Implementation меняются так, что теперь ему нужно реализовать другой интерфейс, такой как IBaz (который он может сделать, не затрагивая ни один из производных классов, если он обеспечивает не абстрактную реализацию), то у вас есть два варианта:

  • Оставьте все определения производных классов без явного объявления новой информации интерфейса, и в этом случае определение класса теперь некорректно в соответствии со стандартом и может ввести в заблуждение, если люди ожидают, что стандарт всегда будет соблюдаться.

  • Перейдите и найдите все производные классы и все их производные классы и исправьте объявления на них. Это требует времени, несколько склонны к ошибкам и трудно сделать полностью, и превращает ваше одиночное изменение файла в многофайльную регистрацию.

Ни один из этих вариантов не привлекателен, поэтому я бы пошел с вариантом, который не помещает вас ни в одну из ситуаций. Просто объявите наиболее производный интерфейс.

  • 0
    Я не стал бы беспокоиться об этом, когда учусь на уроке. В случае интерфейсов, однако, вы обычно не ожидаете наследования, и перечисление обоих прояснит это.
6

Дополнительная информация не нужна компилятору, но может быть полезной для читателя вашего кода, так как читателю не нужно знать, что IBar extends IFoo. Примером этого в структуре будет List<T>, который реализует <IList<T>, ICollection<T> и IEnumerable<T>, хотя IList<T>; расширяет как ICollection<T>, так и IEnumerable<T>.

EDIT. По-моему, для меня, по крайней мере, основная причина, по которой я бы назвал, состоит в том, что вы обычно не думаете о наследовании интерфейсов друг от друга. Когда вы выходите из класса, вы ожидаете, что вы наследуете поведение, которое может наследоваться. Если вас это интересует, вы следуете за производством иерархии классов. С интерфейсом более необычно, что интерфейс будет выведен, и, следовательно, вы вряд ли будете выглядеть и, скорее всего, пропустите соединение. Листинг их обоих решает эту проблему без особых проблем.

  • 0
    @tvanfosson: разве причина, по которой фреймворк делает это, не связана с привязкой данных?
  • 0
    @ Митч - да, это также было бы необходимо, если бы вы явно реализовали любой из интерфейсов. Тем не менее, если бы у меня была иерархия наследования интерфейсов, я бы, вероятно, перечислил интерфейсы. Зачем читателю угадывать, какие интерфейсы реализованы?
1

Тот факт, что вы уже реализовали IFoo в IBar, означает, что вам даже не нужно указывать, что ваш конкретный класс реализации реализует IFoo; CLR может это сделать, и если вы используете Reflector на своей сборке, вы увидите, что Implementation реализует как IFoo, так и IBar, даже если вы используете подход A.

Итак, подход A это.

1

Я бы пошел с A. Вы узнаете, какие методы вам нужно реализовать в самом классе, а инструменты навигации в среде IDE помогут вам с остальными.

B было бы невозможно поддерживать при выполнении любого рефакторинга (например, что произойдет, если вы замените IBar или разделите его на 2?)

0

Я бы выбрал подход A просто потому, что перечисление интерфейса в списке дериваций для определения класса подразумевает, что вы предоставляете реализацию в этом классе. Если вы не собираетесь предоставлять альтернативную реализацию IFoo, я бы не включил ее в список, если только вам это не нужно как простой "интерфейс маркера". Тем не менее, даже тогда во время выполнения оператор "is" (возвращающий true или false) или "as" (возвращающий объект или null) скажет вам, может ли объект быть передан в IFoo.

0

Помимо читаемости и различий в VB.NET (см. комментарии Кэтлин Доллард), возникает ситуация с привязкой данных, которая требует (B). Детали проскользнули у меня (я отредактирую, если кто-то не ударит меня по этому поводу).

Я думаю, что именно поэтому коллекции .NET Framework явно реализуют свои производные интерфейсы.

0

Я думаю, что подход A достаточно ясен, потому что (в VS.NET в любом случае) вы можете очень быстро определить, что IBar реализует IFoo.

Ещё вопросы

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