Для чего используется пустой интерфейс? - PullRequest
3 голосов
/ 19 апреля 2019

Код, с которым я работаю, имеет пустой интерфейс:

public interface ICube {}

У него нет методов или свойств.

Некоторые классы реализуют ICube, а другие интерфейсы наследуются от ICube.
Кто-нибудь, скажите, пожалуйста, чем может быть полезен этот интерфейс ICube?

Ответы [ 2 ]

6 голосов
/ 19 апреля 2019

Вы должны прочитать из MSDN о Interface Design

https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/interface

✓ НЕОБХОДИМО определить интерфейс, если вам нужен какой-то общий API, поддерживаемый набором типов, который включает в себя типы значений.

✓ УЧИТАЙТЕ определение интерфейса, если вам необходимо поддерживать его функциональность для типов, которые уже наследуются от какого-либо другого типа.

X ИЗБЕГАЙТЕ, используя маркерные интерфейсы (интерфейсы без элементов).

Если вам нужно пометить класс как имеющий определенную характеристику (маркер), обычно используйте пользовательский атрибут, а не интерфейс.

✓ НЕОБХОДИМО предоставить хотя бы один тип, являющийся реализацией интерфейса.

Это помогает проверить дизайн интерфейса. Например, List является реализацией интерфейса IList.

✓ НЕОБХОДИМО предоставить хотя бы один API, который использует каждый определенный вами интерфейс (метод, принимающий интерфейс в качестве параметра или свойство, типизированное в качестве интерфейса).

Это поможет проверить дизайн интерфейса. Например, List.Sort использует интерфейс System.Collections.Generic.IComparer.

X НЕ добавлять участников в интерфейс, который был ранее отправлен.

Дополнительная информация: Пустой интерфейс Запах кода пустых интерфейсов?

Маркерный интерфейс Для чего нужен интерфейс маркера?

4 голосов
/ 19 апреля 2019

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

Хотя я использовал маркерные интерфейсы, вот иллюстрация проблемы, которую они создают. Предположим, у меня есть List<ICube>. Возможно, я получаю его в качестве аргумента метода.

public interface ICube {} // It's empty!

public void DoSomethingWithTheseCubes(List<ICube> cubes)
{
    foreach(var cube in cubes)
    {
        // what do I do with this cube?
    }
}

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

public void DoSomethingWithTheseCubes(List<ICube> cubes)
{
    foreach(var cube in cubes)
    {
        (SomeOtherType)cube.DoSomething();
    }
}

Но если я произнесу это, я вызову ошибку времени выполнения, потому что я не могу точно знать, каков фактический тип времени выполнения каждого объекта. Если я знаю тип времени выполнения, я просто должен сделать это:

public void DoSomethingWithTheseCubes(List<SomeOtherType> things)
{
    foreach(var thing in things)
    {
        thing.DoSomething();
    }
}

Мы не совсем уверены в том, что у нас возникла эта проблема, но использование интерфейса маркера побуждает ее. Он использует интерфейс для чего-то другого, чем его предназначение. Это больше похоже на атрибут или даже комментарий.

Интерфейс имеет два использования, которые работают вместе: во-первых, он описывает члены, которые реализует класс. Во-вторых, это позволяет нам приводить класс, который реализует интерфейс как этот интерфейс. Интерфейсы маркеров не делают ни того, ни другого. Они позволяют нам приводить объект как тип без членов. В лучшем случае это бесполезно, а в худшем - вредно, потому что приводит к еще более сомнительным кастам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...