Это называется «интерфейс маркера». Иногда они используются, чтобы указать, что класс предназначен для определенной цели. Это нежелательная практика.
Хотя я использовал маркерные интерфейсы, вот иллюстрация проблемы, которую они создают. Предположим, у меня есть 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();
}
}
Мы не совсем уверены в том, что у нас возникла эта проблема, но использование интерфейса маркера побуждает ее. Он использует интерфейс для чего-то другого, чем его предназначение. Это больше похоже на атрибут или даже комментарий.
Интерфейс имеет два использования, которые работают вместе: во-первых, он описывает члены, которые реализует класс. Во-вторых, это позволяет нам приводить класс, который реализует интерфейс как этот интерфейс. Интерфейсы маркеров не делают ни того, ни другого. Они позволяют нам приводить объект как тип без членов. В лучшем случае это бесполезно, а в худшем - вредно, потому что приводит к еще более сомнительным кастам.