Почему некоторые структуры наследуют интерфейсы, но не реализуют все их члены?

При программировании на .NET Core я наткнулся на структуру под названием StringValues . Он происходит из сборки Microsoft.Extensions.Primitive и сохраняется в том же пространстве имен. Его исходный код доступен на GitHub .

Я заметил, что он наследует от нескольких интерфейсов:

  • IList<string>
  • ICollection<string>
  • IEnumerable<string>
  • IEnumerable
  • IReadOnlyList<string>
  • IReadOnlyCollection<string>
  • IEquatable<StringValues>
  • IEquatable<string>
  • IEquatable<string[]>

Это довольно много для структуры, я бы сказал. Просматривая его методы (в средстве просмотра определений Visual Studio), я заметил, как странно мало он предоставляет. Например, я не видел базовых ICollection<T> как Add() , Clear() или Remove() .

Когда я попытался в явном виде, StringValues экземпляр StringValues к ICollection<string> и использую Add() :

var stringValues = new StringValues("Foo");
var stringCollection = stringValues as ICollection<string>;
stringCollection.Add("Bar");

Я закончил с NotSupportedException бросили при вызове метода Add() :

NotSupportedException: указанный метод не поддерживается.

Поэтому я отправился в исходный код (неоценимые преимущества открытого кода), чтобы посмотреть, что происходит! И тогда я увидел:

void ICollection<string>.Add(string item)
{
    throw new NotSupportedException();
}

void IList<string>.Insert(int index, string item)
{
    throw new NotSupportedException();
}

bool ICollection<string>.Remove(string item)
{
    throw new NotSupportedException();
}

void IList<string>.RemoveAt(int index)
{
    throw new NotSupportedException();
}

void ICollection<string>.Clear()
{
    throw new NotSupportedException();
}

Вопрос

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

В этом случае кажется, что эта структура не предназначена для публичного использования? Такое чувство я испытываю, глядя на реализованный метод Contains() но все же помеченный как внутренний:

bool ICollection<string>.Contains(string item)
{
    return IndexOf(item) >= 0;
}

Всего 1 ответ


Потому что это часто бывает полезно , если вызывающая сторона вызывает только доступные методы. Они могут проверять такие вещи, как IList.IsReadOnly чтобы предвидеть это - если это возвращает false , они должны знать, не ожидать, что Add т. Д. IList.IsReadOnly работать.

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

Точно так же Stream имеет такие вещи, как CanRead и CanWrite , и если любой из них возвращает false , вы можете ожидать, что соответствующие API чтения / записи завершатся с ошибкой.


Есть идеи?

10000