how List<T> does not implement Add(object value)?
-
10-10-2019 - |
Question
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?
Solution
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.
OTHER TIPS
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.
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
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);
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.
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.