2009-09-08 5 views
6

Интерфейс IList требует метода Add. Массивы реализуют эту функцию, но она просто генерирует исключение NotImplementedException. Мне кажется, это очень плохой дизайн.Почему массивы поддерживают IList?

Что думали дизайнеры, когда они это делали?

ответ

7

Иллисты могут быть прочитаны только в том случае, если вызывающий абонент может проверить свойство IsFixedSize перед тем, как попытаться добавить или удалить элемент или свойство IsReadOnly, прежде чем пытаться изменить элемент.

Массив - это IList фиксированного размера.

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

+1

Это свойство 'IsFixedSize', которое вам нужно будет проверить. 'IsReadOnly' будет' false' для массивов, потому что существующие элементы могут быть изменены. 'IsFixedSize' будет' true', потому что элементы не могут быть добавлены или удалены. – LukeH

+0

Просто, чтобы прояснить проблему с помощью исправления и чтения: http://blogs.msdn.com/ericlippert/archive/2009/08/27/what-s-the-difference-between-fixed-and-fixed.aspx – Oliver

+1

@Oliver: Я большой поклонник блога Эрика Липперта, но эта статья не имеет абсолютно никакого отношения к свойствам IsFixedSize или IsReadOnly. – LukeH

0

Поскольку разные объекты имеют разные способности, некоторые интерфейсы включают элементы, которые будут реализованы некоторыми, но не всеми реализациями. Если некоторые, но не все, реализации гипотетического интерфейса IVehicle смогут подключить трейлер, типичным шаблоном будет определение функции AttachTrailer как «Попытка прикрепить трейлер, если CanAttachTrailer истинно, или же выкинуть NotSupportedException" , Все реализации IVehicle будут соответствовать приведенной выше спецификации, независимо от того, могут ли они обрабатывать прицепы.

Преимущество такого подхода состоит в том, что реализации интерфейса могут быть реализованы с множеством различных комбинаций функций без необходимости определять разные типы для разных комбинаций. Другим преимуществом этого подхода является то, что возможен способ Foo, который получает объект, который включает в себя возможности, которые Foo не нужен, чтобы передать этот объект по методу Bar, который нуждается в этих возможностях, не требуя каких-либо приемов в любом месте, и без Foo зная, какие возможности Bar понадобится. Еще одно преимущество заключается в том, что это позволяет легко писать код, который не нуждается в определенных возможностях, но может использовать их, когда они существуют.

Однако есть некоторые недостатки этого подхода. До сих пор нет способа для интерфейса определять спецификации по умолчанию для любых свойств или методов. Следовательно, даже версии IVehicle, которые не могут прикреплять трейлеры, необходимо будет включить код для возврата false в свойство CanAttachTrailer и выбросить исключение в свой метод AttachTrailer. Кроме того, поскольку интерфейс не требует применения многих его методов, не существует способа, который компилятор может знать для отклонения при попытке вызвать функцию, которая требует возможности с объектом типа, который не может его предоставить.

При разработке IList<T> Microsoft, по-видимому, полагала, что преимущества подхода «интерфейс дополнительных возможностей» перевешивают недостатки. В самом деле, если .net предоставил средства для классов, реализующих интерфейсы, для отсрочки реализации по умолчанию для членов, которые они не хотят предоставлять, было бы мало оснований не включать многие дополнительные возможности в интерфейсы базового уровня; для обеспечения возможности компиляции необходимых возможностей можно было бы получить несколько интерфейсов из базы, которая включает в себя все необходимые члены, и указать, что классы, реализующие последние интерфейсы, должны реализовывать определенные элементы способами, которые действительно полезны. Например, Microsoft могла бы определить IResizableList<T> для наследования IList<T> без добавления каких-либо членов, но с ожиданием, что реализации, допускающие изменение размера, будут реализовывать последний интерфейс, тогда как те, которые не позволяют изменять размер, не будут реализовывать его.Если бы они это сделали, код, который должен был иметь возможность изменить размер списка, может потребовать IResizableList<T> (в этом случае он не примет массив), тогда как код, который не должен изменять размер списка, может потребовать IList<T>). К сожалению, Microsoft не делала ничего подобного, поэтому код не может требовать изменения размера списка во время компиляции - все, что он может сделать, это squawk, если список прошедших сообщений сообщает себя как фиксированный.