Why are we unable to add non generic extension methods to generic objects?

I finally got tired of IEnumerable not having an Add method, and decided to add my own through an extension method. My initial attempt was something along these lines:

public static void Add(this IEnumerable<T> items, T item)
{
    ...
}

This threw the expected compiler error about T not being defined, so I changed the signature to Add<T> to define it. (For explanation, see this answer.)

However, this got me thinking. If we create a generic class on our own (like IEnumerable<T>), we are able to add methods to it like the one I had originally tried because T is defined in the class.

I understand that extension methods are not created as a part of the class. There is no "magic" that happens in the compiler to add them to the original class.

I would still think that because of the this declaration on the initial parameter, that the <T> in that parameter could be used to define the type for the method.

My question is this:

Why is there that limitation when it comes to extension methods? Is there something that has been explained for this limitation? Is it something that could be proposed to the language team and added in a future release?

To be more specific, Jonsey reiterated my point a bit more eloquently:

I think I get what you're asking. Why is the compiler not smart enough to recognize, given the method signature, that T is already declared, and doesn't really need to be in the signature?

EDIT

I should have used my new method (Add<T>) before posting as I discovered that when using the method, I don't have to call it generically, I can just use .Add(). I guess that goes along with this answer. I still just find it odd the way it has to be declared, and perhaps that adds a twist to the entire situation.

Argument against duplicate of this question The mentioning of creating IEnumerable<T>.Add() is for illustrative purposes only of the reasoning behind me finding this "peculiarity", and my question is more generic, not specific to that one method.

Jon Skeet
people
quotationmark

Well, you need to ask yourself what's special about T here. Suppose we were to write:

public static void Add(this IEnumerable<X> items, X item)

... would you expect that to work? If so, consider:

public static void Add(this IEnumerable<Button> items, Button item)

Would you expect that to mean the same thing, i.e. effectively be a generic method taking any sequence, or actually only make sense for an IEnumerable<Button> where Button is the System.Windows.Forms.Button class or whatever an appropriate using directive indicates?

Basically, the compiler needs to look up what T means. That can be:

  • A type parameter in the declaring class
  • A type parameter in the declaring method
  • A normal type lookup

In your case, you're in a non-generic class and a non-generic method, so it falls back to a normal type lookup which fails.

Basically you want this to be a type parameter, so it has to be a generic method (or class, but extension methods aren't allowed in generic classes).

If you don't think that the first example (with X) should work, then presumably you're expecting T to be looked up in the context of the IEnumerable<> type, which makes things even odder, as it means that type parameter names become important from "client" code in a way that they aren't anywhere else in the language. It also makes other things tricky. For example:

static void Add(this IEnumerable<T> items, Dictionary<T, T> dict)

Here T is valid for IEnumerable<T>, but Dictionary<,> has TKey, TValue... so should the compiler just say that IEnumerable<T> wins? It ends up being much more confusing than just saying "No, if you want a generic method, you have to declare a type parameter."

people

See more on this question at Stackoverflow