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

14,442

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.

Share:
14,442

Related videos on Youtube

Kornelije Petak
Author by

Kornelije Petak

EDU: MSc.IT @ Faculty of Electrical Engineering and Computing, University of Zagreb, Croatia

Updated on June 22, 2022

Comments

  • Kornelije Petak
    Kornelije Petak almost 2 years

    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.

  • Kornelije Petak
    Kornelije Petak about 8 years
    Thanks for your suggestion, but I know what I can do to solve the problem, and even more, I have written it in the original post. What I wanted is to know why the problem happens, not how to solve it.
  • Chris Wohlert
    Chris Wohlert about 8 years
    @KornelijePetak Oh, sorry for not paying enough attention to your question.
  • Kornelije Petak
    Kornelije Petak about 8 years
    Now that you've said it, it seems obvious to me. T could have been the value type and of course it wouldn't work. Thank you very much. As a follow up, I would like to link to the reason why co(ntra)variance does not work with value types.