Поведение вызвано явной реализацией IList.Add(object)
, а не со / контравариантностью. Согласно документации MSDN, StringCollection явно реализует IList.Add(object)
; Add(string)
метод не связан. Реализация может выглядеть примерно так:
class StringCollection : IList
{
...
public int Add(string value)
{} // implementation
public int IList.Add (object value)
{
if (!value is string)) return -1;
return Add(value as string)
}
}
Это различие можно наблюдать:
StringCollection collection = new StringCollection();
collection.Add(1); // compile error
(collection as IList).Add(1); // compiles, runtime error
(collection as IList).Add((object)"") // calls interface method, which adds string to collection
Добавление
Выше не рассматривается, почему этот шаблон реализован. Спецификация языка C # гласит, что [§13.4.1, акцент добавлен]:
В некоторых случаях имя члена интерфейса может не подходить
для реализующего класса, в этом случае член интерфейса может быть
реализовано с использованием явной реализации интерфейса. [...]
Невозможно получить доступ к явной реализации элемента интерфейса через его полностью определенное имя в вызове метода, доступе к свойству или доступе индексатора. К явной реализации элемента интерфейса можно получить доступ только через экземпляр интерфейса , и в этом случае на него ссылается просто его имя члена.
StringCollection придерживается требуемого поведения IList - IList не гарантирует, что любой произвольный объект может быть добавлен к нему. StringCollection дает более сильные гарантии - прежде всего, то, что он будет содержать только строки. Класс включает в себя собственные строго типизированные методы для Add
, Contains
, Item
и другие для стандартного варианта использования, где к нему обращаются как StringCollection
, а не IList
. Но он по-прежнему прекрасно работает как IList
, принимая и возвращая объекты, но возвращая код ошибки (как позволяет IList), если делается попытка добавить элемент, который не является строкой.
В конечном счете, обнаружение интерфейса в классе (т. Е. Явно ли оно реализовано) остается на усмотрение автора класса. В случае классов инфраструктуры явные реализации включены в документацию MSDN, но недоступны как члены класса (например, показаны в контекстах автозаполнения).