Как List<T> не реализует Add(значение объекта)?
Я считаю, что это довольно глупо, и мне немного стыдно задавать такой вопрос, но я все еще не мог найти ответ:
Я смотрю на класс List<T>
, который реализует IList
,
public class List<T> : IList
один из методов, включенных в список
int Add(object value)
Я это понимаю List<T>
Не следует выставлять этот метод (типа безопасности...), и это действительно не так. Но как это может быть? Разве класс не должен реализовывать весь интерфейс?
6 ответов
Я считаю, что этот (интерфейс) метод реализован явно:
public class List<T> : IList
{
int IList.Add( object value ) {this.Add((T)value);}
}
Таким образом, Add( object )
метод будет скрыт. Вы сможете только позвонить, если вы разыграете List<T>
экземпляр обратно к IList
пример.
Быстрый переход к рефлектору показывает, что IList.Add реализован так:
int IList.Add(object item)
{
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
try
{
this.Add((T) item);
}
catch (InvalidCastException)
{
ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
}
return (this.Count - 1);
}
Другими словами, реализация преобразует его в T, чтобы он заработал, и в случае неудачи вы передаете не T- совместимый тип.
List<T>
явно реализует IList.Add(object value)
вот почему это обычно не видно. Вы можете проверить, выполнив следующие действия:
IList list = new List<string>();
list.Add(new SqlDataReader()); // valid at compile time, will fail at runtime
Он реализует это явно, поэтому вы должны привести к IList
первым использовать его.
List<int> l = new List<int>();
IList il = (IList)l;
il.Add(something);
Вы можете вызвать это, сначала приведя ваш экземпляр списка к интерфейсу:
List<int> lst = new List<int>();
((IList)lst).Add("banana");
И вы получите, как приятно, во время выполнения ArgumentException.
Фредерик прав, что List<T>
Реализация IList
явно для определенных членов, особенно для тех, которые представляют угрозу безопасности типов.
Реализация, которую он предлагает в своем ответе, конечно, не может быть правильной, поскольку она не будет компилироваться.
В подобных случаях типичный подход состоит в том, чтобы приложить все усилия, чтобы попытаться заставить работать интерфейсный элемент, но отказаться, если это невозможно.
Обратите внимание, что IList.Add
Метод определен для возврата:
Позиция, в которую был вставлен новый элемент, или -1, чтобы указать, что элемент не был вставлен в коллекцию.
На самом деле возможна полная реализация:
int IList.Add(object value)
{
if (value is T)
{
Add((T)value);
return Count - 1;
}
return -1;
}
Это всего лишь предположение, конечно. (Если вы действительно хотите знать наверняка, вы всегда можете использовать Reflector.) Он может немного отличаться; например, это может бросить NotSupportedException
, что часто делается для неполных реализаций интерфейса, таких как ReadOnlyCollection<T>
Реализация IList<T>
, Но так как вышесказанное отвечает задокументированным требованиям IList.Add
Я подозреваю, что это близко к реальной вещи.