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.

Patrik Hägne
  • 16,751
  • 5
  • 52
  • 60

1 Answers1

4

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
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 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 Feb 06 '09 at 11:34
  • Which is largely why interfaces exist... add to that list Queue and Stack, for example. – Marc Gravell Feb 06 '09 at 11:43
  • Queues and stacks aren't semantically comparable to simple collections. The same thing could more elegantly be accomplished with the EditorBrowsableAttribute. – Patrik Hägne Feb 06 '09 at 12:36
  • I was not aware of the explicit implementation of Precision and Scale, interesting. – Patrik Hägne Feb 06 '09 at 12:38