{"id":2513,"date":"2010-02-16T10:50:00","date_gmt":"2010-02-16T10:50:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2010\/02\/16\/covariance-and-contravariance-faq\/"},"modified":"2022-10-17T12:47:37","modified_gmt":"2022-10-17T19:47:37","slug":"covariance-and-contravariance-faq","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/covariance-and-contravariance-faq\/","title":{"rendered":"Covariance and Contravariance FAQ"},"content":{"rendered":"<p>In this post I\u2019ll try to answer the most common questions I find on forums and in documentation feedback about C# covariance and contravariance. It\u2019s a big topic for a single blog post, so expect to see a lot of \u201cmore information\u201d links.<\/p>\n<p>Special thanks to <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/ericlippert\/\">Eric Lippert<\/a> and <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/cburrows\/\">Chris Burrows<\/a> for reviewing and providing helpful comments.<\/p>\n<h4>What are covariance and contravariance?<\/h4>\n<p>In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments.Covariance preserves <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/ericlippert\/whats-the-difference-between-covariance-and-assignment-compatibility\">assignment compatibility<\/a> and contravariance reverses it.<\/p>\n<p>The following code demonstrates the difference between assignment compatibility, covariance, and contravariance.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:96738790-2206-4783-806c-a78f365e70a7\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>\/\/ Assignment compatibility.\nstring str = &#8220;test&#8221;;\n\/\/ An object of a more derived type is assigned to an object of a less derived type.\nobject obj = str;<\/p>\n<p>\/\/ Covariance.\nIEnumerable&lt;string&gt; strings = new List&lt;string&gt;();\n\/\/ An object that is instantiated with a more derived type argument\n\/\/ is assigned to an object instantiated with a less derived type argument.\n\/\/ Assignment compatibility is preserved.\nIEnumerable&lt;object&gt; objects = strings;<\/p>\n<p>\/\/ Contravariance.\n\/\/ Assume that I have this method:\n\/\/ static void SetObject(object o) { }\nAction&lt;object&gt; actObject = SetObject;\n\/\/ An object that is instantiated with a less derived type argument\n\/\/ is assigned to an object instantiated with a more derived type argument.\n\/\/ Assignment compatibility is reversed.\nAction&lt;string&gt; actString = actObject;<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>In C#, variance is supported in the following scenarios:<\/p>\n<ol>\n<li>Covariance in arrays (since C# 1.0)<\/li>\n<li>Covariance and contravariance in delegates, also known as \u201cmethod group variance\u201d (since C# 2.0)<\/li>\n<li>Variance for generic type parameters in interfaces and delegates (since C# 4.0)<\/li>\n<\/ol>\n<h4>What is array covariance?<\/h4>\n<p>Arrays are covariant since C# 1.0. You can always do the following:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:a6e078b3-fa32-4b1f-aecf-51e61f72b490\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>object[] obj = new String[10];<\/div>\n<\/div>\n<\/div>\n<p>In the above code, I assigned an array of strings to an array of objects. So I used a more derived type than that originally specified, which is covariance.\nCovariance in arrays is considered \u201cnot safe,\u201d because you can also do this:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:4fa3a44b-9c50-4421-8ce2-3826d0300ff5\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>obj[0] = 5;<\/div>\n<\/div>\n<\/div>\n<p>This code compiles, but it throws an exception at run time because <b>obj<\/b> is in fact an array of strings and cannot contain integers.<\/p>\n<h4>What is delegate, or method group, variance?<\/h4>\n<p>This feature was added in C# 2.0. When you instantiate a delegate, you can assign it a method that has a more derived return type than that specified in the delegate (covariance). You can also assign a method that has parameter types less derived than those in the delegate (contravariance).<\/p>\n<p>Here\u2019s a quick code example illustrating the feature and some of its limitations.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:37645c5e-d640-452a-a5bc-25449541ed7c\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>static object GetObject() { return null; }\nstatic void SetObject(object obj) { }<\/p>\n<p>static string GetString() { return &#8220;&#8221;; }\nstatic void SetString(string str) { }<\/p>\n<p>static void Main()\n{\n\/\/ Covariance. A delegate specifies a return type as object,\n\/\/ but I can assign a method that returns a string.\nFunc&lt;object&gt; del = GetString;<\/p>\n<p>\/\/ Contravariance. A delegate specifies a parameter type as string,\n\/\/ but I can assign a method that takes an object.\nAction&lt;string&gt; del2 = SetObject;<\/p>\n<p>\/\/ But implicit conversion between generic delegates is not supported until C# 4.0.\nFunc&lt;string&gt; del3 = GetString;\nFunc&lt;object&gt; del4 = del3; \/\/ Compiler error here until C# 4.0.\n}<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>By the way, this feature works for all delegates, both generic and non-generic, not just for <b>Func<\/b> and <b>Action<\/b> delegates.<\/p>\n<p>For more information and examples, see <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms173174.aspx\">Covariance and Contravariance in Delegates<\/a> on MSDN and Eric Lippert\u2019s post <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/ericlippert\/covariance-and-contravariance-in-c-part-three-method-group-conversion-variance\">Covariance and Contravariance in C#, Part Three: Method Group Conversion Variance<\/a>.<\/p>\n<h4>What is variance for generic type parameters?<\/h4>\n<p>This is a new feature in C# 4.0. Now, when creating a generic interface, you can specify whether there is an implicit conversion between interface instances that have different type arguments. For example, you can use an interface instance that has methods with more derived return types than originally specified (covariance) or that has methods with less derived parameter types (contravariance). The same rules are applied to generic delegates.<\/p>\n<p>While you can create variant interfaces and delegates yourself, this is not the main purpose for this feature. What is more important is that a set of interfaces and delegates in .NET Framework 4 have been updated to become variant.\nHere\u2019s the list of updated interfaces:<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/9eekhta0(VS.100).aspx\">IEnumerable&lt;T&gt;<\/a> (<i>T<\/i> is covariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/78dfe2yb(VS.100).aspx\">IEnumerator&lt;T&gt;<\/a> (<i>T<\/i> is covariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb351562(VS.100).aspx\">IQueryable&lt;T&gt;<\/a> (<i>T<\/i> is covariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb344977(VS.100).aspx\">IGrouping&lt;TKey, TElement&gt;<\/a> (TKey and TElement are covariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/8ehhxeaf(VS.100).aspx\">IComparer&lt;T&gt;<\/a> (<i>T<\/i> is contravariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms132151(VS.100).aspx\">IEqualityComparer&lt;T&gt;<\/a> (<i>T<\/i> is contravariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/4d7sx9hd(VS.100).aspx\">IComparable&lt;T&gt;<\/a> (<i>T<\/i> is contravariant)<\/li>\n<\/ul>\n<p>And the list of updated delegates:<\/p>\n<ul>\n<li>Action delegates from the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system(VS.100).aspx\">System<\/a> namespace, for example, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/018hxwa8(VS.100).aspx\">Action&lt;T&gt;<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb549311(VS.100).aspx\">Action&lt;T1, T2&gt;<\/a> (<i>T<\/i>, <i>T1<\/i>, <i>T2<\/i>, and so on are contravariant)<\/li>\n<li>Func delegates from the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system(VS.100).aspx\">System<\/a> namespace, for example, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb534960(VS.100).aspx\">Func&lt;TResult&gt;<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb549151(VS.100).aspx\">Func&lt;T, TResult&gt;<\/a> (<i>TResult<\/i> is covariant; <i>T<\/i>, <i>T1<\/i>, <i>T2<\/i>, and so on are contravariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bfcke1bz(VS.100).aspx\">Predicate&lt;T&gt;<\/a> (<i>T<\/i> is contravariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/tfakywbh(VS.100).aspx\">Comparison&lt;T&gt;<\/a> (<i>T<\/i> is contravariant)<\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/kt456a2y(VS.100).aspx\">Converter&lt;TInput, TOutput&gt;<\/a> (<i>TInput<\/i> is contravariant; <i>TOutput<\/i> is covariant.)<\/li>\n<\/ul>\n<p>The most frequent scenario for most users is expected to be something like this one:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:70a393f7-89f2-4bfb-88d0-8d00bcff0da6\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>IEnumerable&lt;Object&gt; objects = new List&lt;String&gt;();<\/div>\n<\/div>\n<\/div>\n<p>While this code doesn\u2019t look that impressive, it allows you to reuse a lot of methods that accept <b>IEnumerable<\/b> objects.<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:9175d306-481a-4a45-aa4f-317697622235\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>class Program\n{\n\/\/ The method has a parameter of the IEnumerable&lt;Person&gt; type.\npublic static void PrintFullName(IEnumerable&lt;Person&gt; persons)\n{\n\/\/ The method iterates through a sequence and prints some info.\n}<\/p>\n<p>public static void Main()\n{\nList&lt;Employee&gt; employees = new List&lt;Employee&gt;();<\/p>\n<p>\/\/ I can pass List&lt;Employee&gt;, which is in fact IEnumerable&lt;Employee&gt;,\n\/\/ although the method expects IEnumerable&lt;Person&gt;.\nPrintFullName(employees);\n}\n}<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>A couple of important rules to remember:<\/p>\n<ul>\n<li>This feature works only for generic interfaces and delegates. If you implement a variant generic interface, the implementing class is still invariant. Classes and structs do not support variance in C# 4.0.\nSo the following doesn\u2019t compile:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:3adb0ac5-89f0-4fe5-a1ab-c114a14ff80a\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\/\/ List&lt;T&gt; implements the covariant interface\n\/\/ IEnumerable&lt;out T&gt;. But classes are invariant.\nList&lt;Person&gt; list = new List&lt;Employee&gt;(); \/\/ Compiler error here.<\/div>\n<\/div>\n<\/div>\n<\/li>\n<li>Variance is supported only if a type parameter is a reference type. Variance is not supported for value types.\nThe following doesn\u2019t compile either:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:1ad08e65-a488-4a96-93bd-abcdc9cc7c83\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\/\/ int is a value type, so the code doesn&#8217;t compile.\nIEnumerable&lt;Object&gt; objects = new List&lt;int&gt;(); \/\/ Compiler error here.<\/div>\n<\/div>\n<\/div>\n<\/li>\n<\/ul>\n<h4>Where can I find more examples of using covariance and contravariance?<\/h4>\n<p>I wrote a couple of MSDN topics that show how you can benefit from this new feature. They might help you better understand the principles of covariance and contravariance:<\/p>\n<ul>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd465120(VS.100).aspx\">Using Variance in Interfaces for Generic Collections<\/a><\/li>\n<li><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd465122(VS.100).aspx\">Using Variance for Func and Action Generic Delegates<\/a><\/li>\n<\/ul>\n<p>Also, take a look at the video <a href=\"http:\/\/msdn.microsoft.com\/en-us\/vcsharp\/ee672314.aspx\">How Do I: Use Covariance and Contravariance in VS 2010 Part I?<\/a> by Eric Lippert.<\/p>\n<h4>How can I create variant generic interfaces and delegates myself?<\/h4>\n<p>The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd469487(VS.100).aspx\">out<\/a> keyword marks a type parameter as covariant, and the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd469484(VS.100).aspx\">in<\/a> keyword marks it as contravariant. The two most important rules to remember:<\/p>\n<ul>\n<li>You can mark a generic type parameter as covariant if it is used only as a method return type and is not used as a type of formal method parameters.<\/li>\n<li>And vice versa, you can mark a type as contravariant if it is used only as a type of formal method parameters and not used as a method return type.<\/li>\n<\/ul>\n<p>For more information about variance validation, read <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd997386(VS.100).aspx\">Creating Variant Generic Interfaces<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd233060(VS.100).aspx\">Variance in Delegates<\/a> on MSDN and Eric Lippert\u2019s post <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/ericlippert\/\">Exact rules for variance validity<\/a>.<\/p>\n<p>This example shows how to create a variant generic interface:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:e577173c-4705-4428-9491-a730ea7ddd06\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>interface IVariant&lt;out R, in A&gt;\n{\n\/\/ These methods satisfy the rules.\nR GetR();\nvoid SetA(A sampleArg);\nR GetRSetA(A sampleArg);<\/p>\n<p>\/\/ And these don\u2019t.\n\/\/ A GetA();\n\/\/ void SetR(R sampleArg);\n\/\/ A GetASetR(R sampleArg);\n}<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>If you extend a variant interface, the extending interface is invariant by default. You must explicitly specify whether the type parameters are covariant or contravariant by using the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd469487(VS.100).aspx\">out<\/a> or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd469484(VS.100).aspx\">in<\/a> keyword. Here is a quick example from <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd997386(VS.100).aspx\">MSDN<\/a>:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6bbc18ac-c931-45b6-a473-92a1543259fe\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>\n<p>interface ICovariant&lt;out T&gt; { }<\/p>\n<p>\/\/ This interface is invariant because I didn&#8217;t use the &#8220;out&#8221; keyword.\ninterface IInvariant&lt;T&gt; : ICovariant&lt;T&gt; { }<\/p>\n<p>\/\/ And this one is covariant because I explicitly specified this.\ninterface IExtCovariant&lt;out T&gt; : ICovariant&lt;T&gt; { }<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>And once again, this feature is supported for generic interfaces and delegates only. So the following doesn\u2019t compile:<\/p>\n<div id=\"scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:42706b24-41bd-44cf-9b37-227b5e8f30f2\" class=\"wlWriterEditableSmartContent\">\n<div>\n<div>class Sample&lt;out T&gt; { }\u00a0\u00a0\/\/ Compiler error here.<\/div>\n<\/div>\n<\/div>\n<p>For more examples, take a look at the video <a href=\"http:\/\/msdn.microsoft.com\/en-us\/vcsharp\/ee672319.aspx\">How Do I: Use Covariance and Contravariance in VS 2010 Part II?<\/a> by Eric Lippert.<\/p>\n<h4>Where can I find more in-depth information about covariance and contravariance?<\/h4>\n<p>This is the MSDN root topic: <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ee207183(VS.100).aspx\">Covariance and Contravariance<\/a>.<\/p>\n<p>And, of course, read <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/ericlippert\/\">Eric Lippert\u2019s blog<\/a>. He designed this feature for C# 4.0, so who knows more about it?<\/p>\n<p><img width=\"1\" height=\"1\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post I\u2019ll try to answer the most common questions I find on forums and in documentation feedback about C# covariance and contravariance. It\u2019s a big topic for a single blog post, so expect to see a lot of \u201cmore information\u201d links. Special thanks to Eric Lippert and Chris Burrows for reviewing and providing [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[3,5],"class_list":["post-2513","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-net-framework","tag-csharp"],"acf":[],"blog_post_summary":"<p>In this post I\u2019ll try to answer the most common questions I find on forums and in documentation feedback about C# covariance and contravariance. It\u2019s a big topic for a single blog post, so expect to see a lot of \u201cmore information\u201d links. Special thanks to Eric Lippert and Chris Burrows for reviewing and providing [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2513","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=2513"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/2513\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=2513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=2513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=2513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}