как List <T>не реализует Add (значение объекта)? - PullRequest
5 голосов
/ 08 декабря 2010

Я считаю, что это довольно глупо, и мне немного неловко задавать такой вопрос, но я все еще не мог найти ответ:

Я смотрю на класс List<T>, который реализует IList.

public class List<T> : IList

один из методов, включенных в Ilist:

int Add(object value)

Я понимаю, что List<T> не должен подвергать этот метод (тип безопасности ...), идействительно нет.Но как это может быть?Разве класс не должен реализовывать весь интерфейс?

Ответы [ 6 ]

10 голосов
/ 08 декабря 2010

Я считаю, что этот (интерфейсный) метод реализован явно :

public class List<T> : IList
{
     int IList.Add( object value ) {this.Add((T)value);}
}

При этом метод Add( object ) будет скрыт. Вы сможете вызвать его, только если приведете экземпляр List<T> обратно к экземпляру IList.

3 голосов
/ 08 декабря 2010

Быстрый переход к рефлектору показывает, что 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 совместимый тип.

2 голосов
/ 08 декабря 2010

List<T> явно реализует IList.Add(object value), поэтому его обычно не видно.Вы можете проверить, выполнив следующие действия:

IList list = new List<string>();
list.Add(new SqlDataReader()); // valid at compile time, will fail at runtime
1 голос
/ 08 декабря 2010

Фредерик прав , что 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, я подозреваю, что оно близко к реальному.

1 голос
/ 08 декабря 2010

Вы можете вызвать его, сначала приведя экземпляр списка к интерфейсу:

List<int> lst = new List<int>();
((IList)lst).Add("banana");

И вы получите ArgumentException как приятно, во время выполнения.

1 голос
/ 08 декабря 2010

Он реализует это явно, поэтому вы должны сначала привести к IList, чтобы использовать его.

List<int> l = new List<int>();
IList il = (IList)l;
il.Add(something);
...