how List<T> does not implement Add(object value)?
Asked Answered
A

6

5

I believe it's pretty stupid, and I am a bit embarrassed to ask this kind of question, but I still could not find the answer:

I am looking at the class List<T> , which implemetns IList.

public class List<T> : IList

one of the methods included in Ilist is

int Add(object value)

I understand that List<T> should not expose that method (type safety...), and it really does not. But how can it be? mustnt class implement the entire interface?

Ametropia answered 8/12, 2010 at 14:48 Comment(4)
I'm not sure what you mean by not exposing it, interfaces can only have public members.Aude
@Brad: List<T> is not an interface, and he's saying that List<T> should not expose it.Ogburn
It is called "Explicit interface implementation".Pyroxylin
Ahh, coffee deprivation; I understand the question now, it's what happens when you skim between sips. Also why I posted a comment not an answer. ;pAude
P
10

I believe that this (interface) method is implemented explicitly:

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

By doing so, the Add( object ) method will by hidden. You'll only able to call it, if you cast the List<T> instance back to an IList instance.

Prestigious answered 8/12, 2010 at 14:50 Comment(1)
You're right about the explicit implementation. But you should fix your example ("recursion" and "can't compile" keep popping up in my mind)... :)Lofton
B
3

A quick trip to reflector shows that IList.Add is implemented like this:

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);
}

In other words, the implementation casts it to T to make it work and fails it you pass a non T compatible type in.

Babs answered 8/12, 2010 at 14:54 Comment(2)
The information is correct, but it doesn't answer the question.Viper
Sure it does. IList.Add does a cast and calls the IList<T>.Add implementation.Babs
P
2

List<T> explicitly implements IList.Add(object value) which is why it's not typically visible. You can test by doing the following:

IList list = new List<string>();
list.Add(new SqlDataReader()); // valid at compile time, will fail at runtime
Primogeniture answered 8/12, 2010 at 14:50 Comment(0)
H
1

It implements it explicitly, so you have to cast to IList first to use it.

List<int> l = new List<int>();
IList il = (IList)l;
il.Add(something);
Hobgoblin answered 8/12, 2010 at 14:51 Comment(0)
E
1

You can call it be casting your list instance to the interface first:

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

And you'll get as nice, runtime, ArgumentException.

Emotionalize answered 8/12, 2010 at 14:53 Comment(0)
F
1

Frederik is right that List<T>'s implementation of IList is explicit for certain members, particularly those that pose a threat to type safety.

The implementation he suggests in his answer can't be right, of course, since it wouldn't compile.

In cases like this, the typical approach is to make a valiant effort to try to get the interface member to work, but to give up if it's impossible.

Note that the IList.Add method is defined to return:

The position into which the new element was inserted, or -1 to indicate that the item was not inserted into the collection.

So in fact, a full implementation is possible:

int IList.Add(object value)
{
    if (value is T)
    {
        Add((T)value);
        return Count - 1;
    }

    return -1;
}

This is just a guess, of course. (If you really want to know for sure, you can always use Reflector.) It may be slightly different; for example it could throw a NotSupportedException, which is often done for incomplete interface implementations such as ReadOnlyCollection<T>'s implementation of IList<T>. But since the above meets the documented requirements of IList.Add, I suspect it's close to the real thing.

Ferrante answered 8/12, 2010 at 14:54 Comment(1)
The actual implementation (at least in .NET4) throws an ArgumentException if you attempt to add an item of the wrong type. (And, if I recall correctly, there was a small bug prior to .NET4 where trying to add null to a List<Nullable<T>> via IList.Add would also erroneously throw the exception.)Engaging

© 2022 - 2024 — McMap. All rights reserved.