Почему в .NET нет интерфейса IArray (T)?

Обновление 2011-Янв-06:

Верьте или нет, я пошел вперед и включил этот интерфейс вбиблиотека с открытым исходным кодом, которую я начал, Tao.NET, янаписал сообщение в блоге объясняя эту библиотекуIArray<T> интерфейс, который не только решает проблемы, которые я первоначально поднял в этом вопросе (год назад ?!), но также обеспечиваетковариантный индексированный интерфейсчто-то очень не хватает (по моему мнению) в BCL.

Вопрос (вкратце):

Я спросил, почему .NET имеетIList<T>, который реализуетICollection<T> и, следовательно, предоставляет методы для изменения списка (Add, Removeи т. д.), но не предлагает никакого промежуточного интерфейса, такого какIArray<T> обеспечить произвольный доступ по индексу без какой-либо модификации списка.

РЕДАКТИРОВАТЬ 2010-Jan-21 14:22 EST:

В комментарии к первоначальному ответу Джона Скита (в котором он задал вопрос, как часто нужно иметь контракт, такой какIArray<T>Я упомянул, чтоKeys а такжеValues свойстваSortedList<TKey, TValues> классIList<TKey> а такжеIList<Value>соответственно на что Джон ответил:

Но в этом случае он объявлен как IList, и вы знаете, просто использовать индексаторы. , , , Это не очень элегантно, я согласен - но на самом деле это не причиняет мне никакой боли.

Это разумно, но я бы ответил, чтоэто не причинит вам никакой боли, потому что вы простознать ты не можешь сделать это, Нопричина ты знаешьне что это ясно из кода; это то, что у вас есть опыт работы сSortedList<TKey, TValue> класс.

Visual Studio не собирается давать мне никаких предупреждений, если я сделаю это:

SortedList<string, int> mySortedList = new SortedList<string, int>();

// ...

IList<string> keys = mySortedList.Keys;
keys.Add("newkey");

Это законно, в соответствии сIList<string>, Но мы все знаем, что это вызовет исключение.

Гийом также сделал правильное замечание:

Ну, интерфейсы не идеальны, но разработчик может проверить свойство IsReadOnly перед вызовом Add / Remove / Set ...

Опять же, это разумно,НО: это не кажется вам немного окольным?

Предположим, я определил интерфейс следующим образом:

public interface ICanWalkAndRun {
    bool IsCapableOfRunning { get; }

    void Walk();
    void Run();
}

Теперь предположим также, что я сделал это обычной практикой для реализации этого интерфейса, но только для егоWalk Способ; во многих случаях я бы решил установитьIsCapableOfRunning вfalse и броситьNotSupportedException наRun...

Тогда у меня мог бы быть некоторый код, который был бы похож на это:

var walkerRunners = new Dictionary<string, ICanWalkAndRun>();

// ...

ICanWalkAndRun walkerRunner = walkerRunners["somekey"];

if (walkerRunner.IsCapableOfRunning) {
    walkerRunner.Run();
} else {
    walkerRunner.Walk();
}

Я сумасшедший, или это своего рода поражение цели интерфейса под названиемICanWalkAndRun?

Оригинальный пост

Я нахожу очень странным, что в .NET, когда я разрабатываю класс со свойством коллекции, которое обеспечивает произвольный доступ по индексу (или метод, который возвращает индексированную коллекцию и т. Д.),но не должен или не может быть изменен путем добавления / удаления элементови если я хочу «сделать правильные вещи» в ООП и предоставить интерфейс, чтобы я мог изменить внутреннюю реализацию, не нарушая API, я должен идти сIList<T>.

Кажется, что стандартный подход заключается в реализацииIList<T> это явно определяет методыAdd, Insertи т. д. - как правило, делая что-то вроде:

private List<T> _items;
public IList<T> Items {
    get { return _items.AsReadOnly(); }
}

Но я вроде как ненавижу это. Если другой разработчик использует мой класс, и у моего класса есть свойство типаIList<T>, а такжевся идея интерфейса: «это некоторые доступные свойства и методы»зачем мне бросатьNotSupportedException (или в любом случае), когда он / она пытается сделать что-то, что, согласно интерфейсу, должно быть полностью законным?

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

Кажется, должно быть что-то вродеIArray<T> интерфейс, который обеспечивает очень простой произвольный доступ по индексу, но не добавляет / удаляет, как показано ниже:

public interface IArray<T> {
    int Length { get; }
    T this[int index] { get; }
}

А потомIList<T> мог бы реализоватьICollection<T> а такжеIArray<T> и добавить егоIndexOf, Insert а такжеRemoveAt методы.

Конечно, я всегда мог бы написать этот интерфейс и использовать его сам, но это не помогает со всеми существующими классами .NET, которые его не реализуют. (И да, я знаю, что мог бы написать обертку, которая берет любойIList<T> и выплевываетIArray<T>, но серьезно?)

Кто-нибудь знает, почему интерфейсы вSystem.Collections.Generic были разработаны таким образом? Я что-то пропустил? Есть ли веский аргументпротив что я говорю о моих проблемах с подходом явного определения членовIList<T>?

Я не пытаюсь казаться дерзким, как будто я знаю лучше, чем люди, которые разрабатывали классы и интерфейсы .NET; это просто не имеет смысламне, Но я готов признать, что есть много вещей, которые я, вероятно, не учел.

Ответы на вопрос(3)

Ваш ответ на вопрос