Kornelije Petak
Kornelije Petak

Reputation: 9562

Why is IEnumerable(of T) not accepted as extension method receiver

Complete question before code:

Why is IEnumerable<T> where T : ITest not accepted as receiver of an extension method that expects this IEnumerable<ITest>?

And now the code:

I have three types:

public interface ITest { }
public class Element : ITest { }
public class ElementInfo : ITest { }

And two extension methods:

public static class Extensions
{
    public static IEnumerable<ElementInfo> Method<T>(
        this IEnumerable<T> collection) 
        where T : ITest
    {
→        return collection.ToInfoObjects();
    }

    public static IEnumerable<ElementInfo> ToInfoObjects(
        this IEnumerable<ITest> collection)
    {
        return collection.Select(item => new ElementInfo());
    }
}

The compiler error I get (on the marked line):

CS1929 : 'IEnumerable<T>' does not contain a definition for 'ToInfoObjects' and the best extension method overload 'Extensions.ToInfoObjects(IEnumerable<ITest>)' requires a receiver of type 'IEnumerable<ITest>'

Why is this so? The receiver of the ToInfoObjects extension method is an IEnumerable<T> and by the generic type constraint, T must implement ITest.

Why is then the receiver not accepted? My guess is the covariance of the IEnumerable<T> but I am not sure.

If I change ToInfoObjects to receive IEnumerable<T> where T : ITest, then everything is ok.

Upvotes: 18

Views: 15642

Answers (2)

user4003407
user4003407

Reputation: 22102

Consider this:

public struct ValueElement : ITest { }

and this:

IEnumerable<ValueElement> collection = ...
collection.Method(); //OK, ValueElement implement ITest, as required.
collection.ToInfoObjects() //Error, IEnumerable<ValueElement> is not IEnumerable<ITest>
                           //variance does not work with value types.

So that not every type allowed for Method also allowed for ToInfoObjects. If you add class constraint to T in Method, then your code will compile.

Upvotes: 14

Chris Wohlert
Chris Wohlert

Reputation: 600

You can do the following:

    public static IEnumerable<ElementInfo> Method<T>(
        this IEnumerable<T> collection)
        where T : ITest
    {
        return collection.ToInfoObjects();
    }

    public static IEnumerable<ElementInfo> ToInfoObjects<T>(
        this IEnumerable<T> collection)
    {
        return collection.Select(item => new ElementInfo());
    }

Notice on ToInfoObjects.

Upvotes: -1

Related Questions