Problem understanding covariance contravariance with generics in C#

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite












I can't understand why the following C# code doesn't compile.



As you can see, I have a static generic method Something with an IEnumerable<T> parameter (and T is constrained to be an IA interface), and this parameter can't be implicitly converted to IEnumerable<IA>.



Can someone explain it to me (I don't search for a workaround, just to understand why it doesn't work).



public interface IA 
public interface IB : IA
public class CIA : IA
public class CIAD : CIA
public class CIB : IB
public class CIBD : CIB

public static class Test

public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA

var bar = foo.ToList();

// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());

// This call is illegal
Something2(bar);

return bar;


private static void Something2(IEnumerable<IA> foo)





Error I get in Something2(bar) line:



 Argument 1: cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.IEnumerable<ConsoleApp20.Program.IA>'









share|improve this question









New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 2




    Possible duplicate of Why covariance and contravariance do not support value type
    – Dirk
    20 mins ago






  • 2




    You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
    – Dirk
    19 mins ago






  • 1




    @SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
    – Eric Lippert
    9 mins ago















up vote
6
down vote

favorite












I can't understand why the following C# code doesn't compile.



As you can see, I have a static generic method Something with an IEnumerable<T> parameter (and T is constrained to be an IA interface), and this parameter can't be implicitly converted to IEnumerable<IA>.



Can someone explain it to me (I don't search for a workaround, just to understand why it doesn't work).



public interface IA 
public interface IB : IA
public class CIA : IA
public class CIAD : CIA
public class CIB : IB
public class CIBD : CIB

public static class Test

public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA

var bar = foo.ToList();

// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());

// This call is illegal
Something2(bar);

return bar;


private static void Something2(IEnumerable<IA> foo)





Error I get in Something2(bar) line:



 Argument 1: cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.IEnumerable<ConsoleApp20.Program.IA>'









share|improve this question









New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 2




    Possible duplicate of Why covariance and contravariance do not support value type
    – Dirk
    20 mins ago






  • 2




    You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
    – Dirk
    19 mins ago






  • 1




    @SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
    – Eric Lippert
    9 mins ago













up vote
6
down vote

favorite









up vote
6
down vote

favorite











I can't understand why the following C# code doesn't compile.



As you can see, I have a static generic method Something with an IEnumerable<T> parameter (and T is constrained to be an IA interface), and this parameter can't be implicitly converted to IEnumerable<IA>.



Can someone explain it to me (I don't search for a workaround, just to understand why it doesn't work).



public interface IA 
public interface IB : IA
public class CIA : IA
public class CIAD : CIA
public class CIB : IB
public class CIBD : CIB

public static class Test

public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA

var bar = foo.ToList();

// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());

// This call is illegal
Something2(bar);

return bar;


private static void Something2(IEnumerable<IA> foo)





Error I get in Something2(bar) line:



 Argument 1: cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.IEnumerable<ConsoleApp20.Program.IA>'









share|improve this question









New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I can't understand why the following C# code doesn't compile.



As you can see, I have a static generic method Something with an IEnumerable<T> parameter (and T is constrained to be an IA interface), and this parameter can't be implicitly converted to IEnumerable<IA>.



Can someone explain it to me (I don't search for a workaround, just to understand why it doesn't work).



public interface IA 
public interface IB : IA
public class CIA : IA
public class CIAD : CIA
public class CIB : IB
public class CIBD : CIB

public static class Test

public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA

var bar = foo.ToList();

// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());

// This call is illegal
Something2(bar);

return bar;


private static void Something2(IEnumerable<IA> foo)





Error I get in Something2(bar) line:



 Argument 1: cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.IEnumerable<ConsoleApp20.Program.IA>'






c# covariance






share|improve this question









New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 19 mins ago









Luiso

2,18921844




2,18921844






New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 30 mins ago









BenLaz

1343




1343




New contributor




BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






BenLaz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 2




    Possible duplicate of Why covariance and contravariance do not support value type
    – Dirk
    20 mins ago






  • 2




    You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
    – Dirk
    19 mins ago






  • 1




    @SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
    – Eric Lippert
    9 mins ago













  • 2




    Possible duplicate of Why covariance and contravariance do not support value type
    – Dirk
    20 mins ago






  • 2




    You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
    – Dirk
    19 mins ago






  • 1




    @SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
    – Eric Lippert
    9 mins ago








2




2




Possible duplicate of Why covariance and contravariance do not support value type
– Dirk
20 mins ago




Possible duplicate of Why covariance and contravariance do not support value type
– Dirk
20 mins ago




2




2




You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
– Dirk
19 mins ago




You have not restricted T to reference types. If you use the condition where T: class, IA then it should work. The linked answer has more details.
– Dirk
19 mins ago




1




1




@SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
– Eric Lippert
9 mins ago





@SeM: Please do not use the comment system to complain; use comments to request clarification of the question.
– Eric Lippert
9 mins ago













1 Answer
1






active

oldest

votes

















up vote
13
down vote













The error message is insufficiently informative, and that is my fault. Sorry about that.



The problem you are experiencing is a consequence of the fact that covariance only works on reference types.



Now, you're probably saying "but IA is a reference type" right now. Yes, it is. But you didn't say that T is IA. You said that T is a type which implements IA, and a value type can implement an interface.



If you want covariance to work you have to tell the compiler that the type parameter is a reference type with the class constraint as well as the IA interface constraint.



The error message really should say that the conversion is not possible because covariance requires a guarantee of reference-type-ness, since that is the fundamental problem.






share|improve this answer




















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );






    BenLaz is a new contributor. Be nice, and check out our Code of Conduct.









     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53185806%2fproblem-understanding-covariance-contravariance-with-generics-in-c-sharp%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    13
    down vote













    The error message is insufficiently informative, and that is my fault. Sorry about that.



    The problem you are experiencing is a consequence of the fact that covariance only works on reference types.



    Now, you're probably saying "but IA is a reference type" right now. Yes, it is. But you didn't say that T is IA. You said that T is a type which implements IA, and a value type can implement an interface.



    If you want covariance to work you have to tell the compiler that the type parameter is a reference type with the class constraint as well as the IA interface constraint.



    The error message really should say that the conversion is not possible because covariance requires a guarantee of reference-type-ness, since that is the fundamental problem.






    share|improve this answer
























      up vote
      13
      down vote













      The error message is insufficiently informative, and that is my fault. Sorry about that.



      The problem you are experiencing is a consequence of the fact that covariance only works on reference types.



      Now, you're probably saying "but IA is a reference type" right now. Yes, it is. But you didn't say that T is IA. You said that T is a type which implements IA, and a value type can implement an interface.



      If you want covariance to work you have to tell the compiler that the type parameter is a reference type with the class constraint as well as the IA interface constraint.



      The error message really should say that the conversion is not possible because covariance requires a guarantee of reference-type-ness, since that is the fundamental problem.






      share|improve this answer






















        up vote
        13
        down vote










        up vote
        13
        down vote









        The error message is insufficiently informative, and that is my fault. Sorry about that.



        The problem you are experiencing is a consequence of the fact that covariance only works on reference types.



        Now, you're probably saying "but IA is a reference type" right now. Yes, it is. But you didn't say that T is IA. You said that T is a type which implements IA, and a value type can implement an interface.



        If you want covariance to work you have to tell the compiler that the type parameter is a reference type with the class constraint as well as the IA interface constraint.



        The error message really should say that the conversion is not possible because covariance requires a guarantee of reference-type-ness, since that is the fundamental problem.






        share|improve this answer












        The error message is insufficiently informative, and that is my fault. Sorry about that.



        The problem you are experiencing is a consequence of the fact that covariance only works on reference types.



        Now, you're probably saying "but IA is a reference type" right now. Yes, it is. But you didn't say that T is IA. You said that T is a type which implements IA, and a value type can implement an interface.



        If you want covariance to work you have to tell the compiler that the type parameter is a reference type with the class constraint as well as the IA interface constraint.



        The error message really should say that the conversion is not possible because covariance requires a guarantee of reference-type-ness, since that is the fundamental problem.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 19 mins ago









        Eric Lippert

        527k14310361917




        527k14310361917




















            BenLaz is a new contributor. Be nice, and check out our Code of Conduct.









             

            draft saved


            draft discarded


















            BenLaz is a new contributor. Be nice, and check out our Code of Conduct.












            BenLaz is a new contributor. Be nice, and check out our Code of Conduct.











            BenLaz is a new contributor. Be nice, and check out our Code of Conduct.













             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53185806%2fproblem-understanding-covariance-contravariance-with-generics-in-c-sharp%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            What does second last employer means? [closed]

            List of Gilmore Girls characters

            Confectionery