Почему основные типы реализуют интерфейсы только частично? - PullRequest
7 голосов
/ 20 мая 2011

Q1 Почему новые классы из .NET реализуют интерфейсы только частично?

Q2 Должен ли я сделать то же самое в моем коде?

Я задал этот вопрос здесь , поэтому я подумал: хорошо, это было давно, вы можете использовать по-разному и т. Д., И т. Д., И теперь такая реализация поддерживается только по соображениям согласованности. Но новые классы тоже делают это.

Старый

int[] list = new int[] {};
IList iList = (IList)list;
ilist.Add(1); //exception here

New

ICollection c = new ConcurrentQueue<int>();
var root = c.SyncRoot; //exception here

UPDATE

Я не волнуюсь Почему Я получаю исключения, это понятно. Но я не понимаю , почему классы реализуют четко определенный контракт, но не всех участников (что может привести к неприятным исключениям во время выполнения)?

Ответы [ 4 ]

4 голосов
/ 20 мая 2011

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

В нынешнем виде интерфейсы такие, какие есть. Однако по-прежнему очень удобно реализовывать основные интерфейсы IList[<T>] / ICollection[<T>] / IEnumerable[<T>] - он предлагает большинству абонентов доступ к тому, что им нужно ... так что индексаторы в первом примере и Add во втором.

Чтобы быть справедливым, они также предлагают IsFixedSize и IsReadOnly - запрос первого вынудил бы вас не звонить Add. Re SyncRoot - это предположительно не может иметь смысла внутри ConcurrentQueue<T>, и любая реализация нарушит логику типа. Обычно я бы сказал: «тогда это не тот тип; не реализуйте интерфейс», но повторяю мое предыдущее утверждение ... большинство людей никогда не используют SyncRoot - так что я в порядке с этим; p

2 голосов
/ 20 мая 2011

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

Документация для IList состояний:

IList является потомком ICollectionинтерфейс и является базовым интерфейсом всех неуниверсальных списков.Реализации IList делятся на три категории: только чтение, фиксированный размер и переменный размер.IList только для чтения не может быть изменен.IList фиксированного размера не позволяет добавлять или удалять элементы, но позволяет модифицировать существующие элементы.IList переменного размера позволяет добавлять, удалять и изменять элементы.

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

Почему интерфейс был разработан таким образом?Можно только предполагать, но этот конкретный дизайн позволяет изменять свойства IsFixedSize, IsReadOnly и т. Д. В течение срока службы экземпляра интерфейса.

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

1 голос
/ 20 мая 2011

С точки зрения ООП это просто неправильно.Они должны были либо создавать меньшие интерфейсы, либо не помещать их в такие вещи, как массивы.Однако разработчики .NET Framework не глупы и, вероятно, сделали некоторый компромисс.Например, IEnumerable необходим для реализации IDisposable, что не имеет смысла с точки зрения разработки ООП, но, например, для читателей баз данных есть некоторые преимущества в производительности.Так что, вероятно, реализации, которые взломаны в классе (как ваш пример), имеют некоторую выгоду, но с точки зрения ООП они ошибочны, и вы не должны делать это, если не знаете, для чего вы торгуете хорошим дизайном.

0 голосов
/ 24 мая 2011

Я подозреваю, что существование частично реализованных интерфейсов является следствием решения проекта не разрешать классу или интерфейсу иметь независимые свойства для чтения и записи для одного и того же имени и автоматически использовать их соответствующим образом (например, если класс имеет свойство для чтения 'foo' и свойство для записи 'foo', используйте свойство для чтения для чтения и для записи для записи). Это дизайнерское решение затруднило разделение аспектов чтения и записи определенных интерфейсов.

В идеале, вместо единого интерфейса IList, были бы универсальный контравариантный интерфейс IReadableByIndex, универсальные ковариантные интерфейсы IWriteableByIndex, IAppendable, IGrowableByIndex (включает в себя различные функции вставки и удаления) и неуниверсальный IMovableByIndex (копия на основе индекса, функции swap и roll) и, возможно, IComparableByIndex (с учетом двух индексов сравните элементы). Интерфейс IList мог бы реализовать все это, но также было бы много полезных подмножеств (многие из которых могли бы быть контравариантными или ковариантными). Обратите внимание, что существование некоторых неуниверсальных подпрограмм позволило бы реализовать такие вещи, как сортировки, в любой коллекции, которая реализует IComparableByIndex и IMovableByIndex, не беспокоясь о точном типе коллекции.

К сожалению, для того чтобы разделение IList было действительно полезным, было бы необходимо иметь IReadableByIndex и IWritableByIndex в качестве отдельных интерфейсов. Это, в свою очередь, создало бы трудности при попытке написать код, который бы наследовал оба интерфейса, поскольку компилятор будет жаловаться на неоднозначность при попытке использовать индексированный метод доступа. Так как IReadableByIndex и IWritableByIndex в конечном итоге пришлось объединить, Microsoft, вероятно, полагала, что это может также объединить все в IList.

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