Как 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 Я подозреваю, что это близко к реальной вещи.

Другие вопросы по тегам