views:

328

answers:

1

The Add-method from the ICollection(T) interface has been explicitly implemented by the LinkedList(T)-class. This collection instead have AddFirst- and AddLast-methods (among others). The explicitly implemented method maps to the AddLast-method. This has some drawbacks and IMHO no benefit at all. The two major drawbacks are this:

  1. You can't use collection initialization on a LinkedList(T) since it requires an Add-method.
  2. If you have used let's say a List(T) in a method and want to change it to use a LinkedList(T) instead you'll have to update all calls to Add to call AddLast instead.

The way I think about it is that you should never explicitly implement interface members unless they make no sense at all when you know the concrete type. For example the Add-method should be explicitly implemented (and effectively hidden) if you were implementing a read only ICollection(T).

Are there other examples of methods that have been explicitly implemented that shouldn't have been in the framework?

As a side note: To resolve the number 2 issue you could create an extension method "Add" for the LinkedList(T)-class.

+2  A: 

The Add method would be ambiguous, so I'm content with an explicit implementation...

Queue[<T>] and Stack[<T>] have similar behaviour.

For other (non-collection) curious explicit members - how about DbParameter.Precision and DbParameter.Scale.

Re the issue transferring between the two - you could always write a ToLinkedList<T> extension method on IEnumerable<T>.

Alternatively - an AddRange<T> extension method goes a long way...

static void Main()
{
    var list = new LinkedList<int>();
    list.AddRange(1, 2, 3, 4, 5);
}
static void AddRange<T>(this ICollection<T> list, params T[] values)
{
    foreach (T value in values)
    {
        list.Add(value);
    }
}

(EDIT) You could also use a "fluent" API if you want to be able to use it as a single expression:

static void Main()
{
    var list = new LinkedList<int>().AddRange(1, 2, 3, 4, 5);
    // `list` is correctly a LinkedList<int> here
}
static TCollection AddRange<TCollection, TValue>(
    this TCollection collection, params TValue[] values)
    where TCollection : ICollection<TValue>
{
    foreach (TValue value in values)
    {
        collection.Add(value);
    }
    return collection;
}
Marc Gravell
I guess you mean that it would be ambiguous to the developer? The problem isn't that you can't add a range, the problem is that the interface differs from other ICollections so that they are not interchangeable unless cast to the interface.
Patrik Hägne
Which is largely why interfaces exist... add to that list Queue and Stack, for example.
Marc Gravell
Queues and stacks aren't semantically comparable to simple collections. The same thing could more elegantly be accomplished with the EditorBrowsableAttribute.
Patrik Hägne
I was not aware of the explicit implementation of Precision and Scale, interesting.
Patrik Hägne