{"appState":{"pageLoadApiCallsStatus":true},"articleState":{"article":{"headers":{"creationTime":"2018-01-29T13:04:26+00:00","modifiedTime":"2018-01-29T13:04:26+00:00","timestamp":"2022-02-24T17:04:09+00:00"},"data":{"breadcrumbs":[{"name":"Technology","_links":{"self":"https://dummies-api.dummies.com/v2/categories/33512"},"slug":"technology","categoryId":33512},{"name":"Programming & Web Design","_links":{"self":"https://dummies-api.dummies.com/v2/categories/33592"},"slug":"programming-web-design","categoryId":33592},{"name":"C#","_links":{"self":"https://dummies-api.dummies.com/v2/categories/33596"},"slug":"csharp","categoryId":33596}],"title":"Revising C# Generics","strippedTitle":"revising c# generics","slug":"revising-c-generics","canonicalUrl":"","seo":{"metaDescription":"","noIndex":0,"noFollow":0},"content":"The generics model implemented in C# 2.0 was incomplete. Generics are fine for making the programmer’s life easier, but they did little in that version to make the analyst’s life easier. It used to be very hard to model an actual business model using Generics, and that changed in C# 4.0. Although parameters in C# 2.0 all allowed for variance in several directions, generics did not.\r\n\r\nVariance has to do with types of parameters and return values. <em>Covariance</em> means that an instance of a subclass can be used when an instance of a parent class is expected, while <em>contravariance</em> means that an instance of a superclass can be used when an instance of a subclass is expected. When neither is possible, it is called <em>invariance.</em>\r\n\r\nAll fourth-generation languages support some kind of variance. In C# 3.0 and earlier versions, parameters are covariant, and return types are contravariant. So, this works because string and integer parameters are covariant to object parameters:\r\n\r\n<code>public static void MessageToYou(object theMessage)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>if (theMessage != null)</code>\r\n\r\n<code>Console.Writeline(theMessage)</code>\r\n\r\n<code>}</code>\r\n\r\n<code>//then:</code>\r\n\r\n<code>MessageToYou(\"It's a message, yay!\");</code>\r\n\r\n<code>MessageToYou(4+6.6);</code>\r\n\r\n<code>And this works because object return types are contravariant to string and integer return types (for example):</code>\r\n\r\n<code>object theMessage = MethodThatGetsTheMessage();</code>\r\n\r\nGenerics are invariant in C# 2.0 and 3.0. This means that if <code>Basket<apple></code> is of type <code>Basket<fruit></code>, those <code>Baskets</code> are not interchangeable as strings and objects are in the preceding example.\r\n<h2 id=\"tab1\" >Variance</h2>\r\nIf you look at a method like the following one:\r\n\r\n<code>public static void WriteMessages()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>List<string> someMessages = new List<string>();</code>\r\n\r\n<code>someMessages.Add(\"The first message\");</code>\r\n\r\n<code>someMessages.Add(\"The second message\");</code>\r\n\r\n<code>MessagesToYou(someMessages);</code>\r\n\r\n<code>}</code>\r\n\r\nand then you try to call that method with a string type\r\n\r\n<code>//This doesn't work in C#3!!</code>\r\n\r\n<code>public static void MessagesToYou(IEnumerable<object> theMessages)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>foreach (var item in theMessages)</code>\r\n\r\n<code>Console.WriteLine(item);</code>\r\n\r\n<code>}</code>\r\n\r\nit will fail. Generics are invariant in C# 3.0. But, in Visual Studio 2010 and later this complies because <code>IEnumerable<T></code> is covariant — you can use a more derived type as a substitute for a higher-order type.\r\n<h2 id=\"tab2\" >Contravariance</h2>\r\nA scheduling application could have <code>Events</code>, which have a date, and then a set of subclasses, one of which is <code>Course</code>. A <code>Course</code> is an <code>Event</code>. Courses know their own number of students. One of these methods is <code>MakeCalendar</code>:\r\n\r\n<code>public void MakeCalendar(IEnumerable<Event> theEvents)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>foreach (Event item in theEvents)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>Console.WriteLine(item.WhenItIs.ToString());</code>\r\n\r\n<code>}</code>\r\n\r\n<code>}</code>\r\n\r\nPretend that it makes a calendar. For now, all it does is print the date to the console. <code>MakeCalendar</code> is systemwide, so it expects some enumerable list of events.\r\n\r\nThe application also has a sort algorithm at the main system called <code>EventSorter</code> that passes a sorted collection into the <code>Sort</code> method. It expects a call from a list of Events. Here is the <code>EventSorter</code> class:\r\n\r\n<code>class EventSorter : IComparer<Event></code>\r\n\r\n<code>{</code>\r\n\r\n<code>public int Compare(Event x, Event y)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>return x.WhenItIs.CompareTo(y.WhenItIs);</code>\r\n\r\n<code>}</code>\r\n\r\n<code>}</code>\r\n\r\nThe event manager makes a list of courses, sorts them, and then makes a calendar. <code>ScheduleCourses</code> creates the list of courses and then calls <code>courses.Sort()</code> with <code>EventSorter</code> as an argument, as shown here:\r\n\r\n<code>public void ScheduleCourses()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>List<Course> courses = new List<Course>()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>new Course(){NumberOfStudents=20,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,2,1)},</code>\r\n\r\n<code>new Course(){NumberOfStudents=14,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,3,1)},</code>\r\n\r\n<code>new Course(){NumberOfStudents=24,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,4,1)},</code>\r\n\r\n<code>};</code>\r\n\r\n<code> </code>\r\n\r\n<code>//Pass an ICompare<Event> class to the List<Course> collection.</code>\r\n\r\n<code>//It should be an ICompare<Course>, but it can use ICompare<Event></code>\r\n\r\n<code>// because of contravariance</code>\r\n\r\n<code>courses.Sort(new EventSorter());</code>\r\n\r\n<code> </code>\r\n\r\n<code> </code>\r\n\r\n<code>//Pass a List of courses, where a List of Events was expected.</code>\r\n\r\n<code>//We can do this because generic parameters are covariant</code>\r\n\r\n<code>MakeCalendar(courses);</code>\r\n\r\n<code>}</code>\r\n\r\nBut wait, this is a list of courses that calls <code>Sort()</code>, not a list of events. Doesn't matter — <code>IComparer<Event></code> is a contravariant generic for T (its return type) as compared to <code>IComparer<Course></code>, so it’s still possible to use the algorithm.\r\n\r\nNow the application passes a list into the <code>MakeSchedule</code> method, but that method expects an enumerable collection of <code>Events</code>. Because parameters are covariant for generics now, it’s possible to pass in a <code>List</code> of <code>courses</code>, as <code>Course</code> is covariant to <code>Event.</code>\r\n\r\nThere is another example of contravariance, using parameters rather than return values. If you have a method that returns a generic list of <code>courses</code>, you can call that method expecting a list of <code>Events</code>, because <code>Event</code> is a superclass of <code>Course</code>.\r\n\r\nYou know how you can have a method that returns a <code>String</code> and assign the return value to a variable that you have declared an object? Now you can do that with a generic collection, too.\r\n\r\nIn general, the C# compiler makes assumptions about the generic type conversion. As long as you’re working up the chain for parameters or down the chain for return types, C# will just magically figure the type out.\r\n<h2 id=\"tab3\" >Covariance</h2>\r\nThe application now passes the list into the <code>MakeSchedule</code> method, but that method expects an enumerable collection of <code>Events</code>. Because parameters are covariant for generics now, it’s possible to pass in a <code>List</code> of <code>courses</code>, as <code>Course</code> is covariant to <code>Event</code>. This is covariance for parameters.","description":"The generics model implemented in C# 2.0 was incomplete. Generics are fine for making the programmer’s life easier, but they did little in that version to make the analyst’s life easier. It used to be very hard to model an actual business model using Generics, and that changed in C# 4.0. Although parameters in C# 2.0 all allowed for variance in several directions, generics did not.\r\n\r\nVariance has to do with types of parameters and return values. <em>Covariance</em> means that an instance of a subclass can be used when an instance of a parent class is expected, while <em>contravariance</em> means that an instance of a superclass can be used when an instance of a subclass is expected. When neither is possible, it is called <em>invariance.</em>\r\n\r\nAll fourth-generation languages support some kind of variance. In C# 3.0 and earlier versions, parameters are covariant, and return types are contravariant. So, this works because string and integer parameters are covariant to object parameters:\r\n\r\n<code>public static void MessageToYou(object theMessage)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>if (theMessage != null)</code>\r\n\r\n<code>Console.Writeline(theMessage)</code>\r\n\r\n<code>}</code>\r\n\r\n<code>//then:</code>\r\n\r\n<code>MessageToYou(\"It's a message, yay!\");</code>\r\n\r\n<code>MessageToYou(4+6.6);</code>\r\n\r\n<code>And this works because object return types are contravariant to string and integer return types (for example):</code>\r\n\r\n<code>object theMessage = MethodThatGetsTheMessage();</code>\r\n\r\nGenerics are invariant in C# 2.0 and 3.0. This means that if <code>Basket<apple></code> is of type <code>Basket<fruit></code>, those <code>Baskets</code> are not interchangeable as strings and objects are in the preceding example.\r\n<h2 id=\"tab1\" >Variance</h2>\r\nIf you look at a method like the following one:\r\n\r\n<code>public static void WriteMessages()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>List<string> someMessages = new List<string>();</code>\r\n\r\n<code>someMessages.Add(\"The first message\");</code>\r\n\r\n<code>someMessages.Add(\"The second message\");</code>\r\n\r\n<code>MessagesToYou(someMessages);</code>\r\n\r\n<code>}</code>\r\n\r\nand then you try to call that method with a string type\r\n\r\n<code>//This doesn't work in C#3!!</code>\r\n\r\n<code>public static void MessagesToYou(IEnumerable<object> theMessages)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>foreach (var item in theMessages)</code>\r\n\r\n<code>Console.WriteLine(item);</code>\r\n\r\n<code>}</code>\r\n\r\nit will fail. Generics are invariant in C# 3.0. But, in Visual Studio 2010 and later this complies because <code>IEnumerable<T></code> is covariant — you can use a more derived type as a substitute for a higher-order type.\r\n<h2 id=\"tab2\" >Contravariance</h2>\r\nA scheduling application could have <code>Events</code>, which have a date, and then a set of subclasses, one of which is <code>Course</code>. A <code>Course</code> is an <code>Event</code>. Courses know their own number of students. One of these methods is <code>MakeCalendar</code>:\r\n\r\n<code>public void MakeCalendar(IEnumerable<Event> theEvents)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>foreach (Event item in theEvents)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>Console.WriteLine(item.WhenItIs.ToString());</code>\r\n\r\n<code>}</code>\r\n\r\n<code>}</code>\r\n\r\nPretend that it makes a calendar. For now, all it does is print the date to the console. <code>MakeCalendar</code> is systemwide, so it expects some enumerable list of events.\r\n\r\nThe application also has a sort algorithm at the main system called <code>EventSorter</code> that passes a sorted collection into the <code>Sort</code> method. It expects a call from a list of Events. Here is the <code>EventSorter</code> class:\r\n\r\n<code>class EventSorter : IComparer<Event></code>\r\n\r\n<code>{</code>\r\n\r\n<code>public int Compare(Event x, Event y)</code>\r\n\r\n<code>{</code>\r\n\r\n<code>return x.WhenItIs.CompareTo(y.WhenItIs);</code>\r\n\r\n<code>}</code>\r\n\r\n<code>}</code>\r\n\r\nThe event manager makes a list of courses, sorts them, and then makes a calendar. <code>ScheduleCourses</code> creates the list of courses and then calls <code>courses.Sort()</code> with <code>EventSorter</code> as an argument, as shown here:\r\n\r\n<code>public void ScheduleCourses()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>List<Course> courses = new List<Course>()</code>\r\n\r\n<code>{</code>\r\n\r\n<code>new Course(){NumberOfStudents=20,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,2,1)},</code>\r\n\r\n<code>new Course(){NumberOfStudents=14,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,3,1)},</code>\r\n\r\n<code>new Course(){NumberOfStudents=24,</code>\r\n\r\n<code>WhenItIs = new DateTime(2018,4,1)},</code>\r\n\r\n<code>};</code>\r\n\r\n<code> </code>\r\n\r\n<code>//Pass an ICompare<Event> class to the List<Course> collection.</code>\r\n\r\n<code>//It should be an ICompare<Course>, but it can use ICompare<Event></code>\r\n\r\n<code>// because of contravariance</code>\r\n\r\n<code>courses.Sort(new EventSorter());</code>\r\n\r\n<code> </code>\r\n\r\n<code> </code>\r\n\r\n<code>//Pass a List of courses, where a List of Events was expected.</code>\r\n\r\n<code>//We can do this because generic parameters are covariant</code>\r\n\r\n<code>MakeCalendar(courses);</code>\r\n\r\n<code>}</code>\r\n\r\nBut wait, this is a list of courses that calls <code>Sort()</code>, not a list of events. Doesn't matter — <code>IComparer<Event></code> is a contravariant generic for T (its return type) as compared to <code>IComparer<Course></code>, so it’s still possible to use the algorithm.\r\n\r\nNow the application passes a list into the <code>MakeSchedule</code> method, but that method expects an enumerable collection of <code>Events</code>. Because parameters are covariant for generics now, it’s possible to pass in a <code>List</code> of <code>courses</code>, as <code>Course</code> is covariant to <code>Event.</code>\r\n\r\nThere is another example of contravariance, using parameters rather than return values. If you have a method that returns a generic list of <code>courses</code>, you can call that method expecting a list of <code>Events</code>, because <code>Event</code> is a superclass of <code>Course</code>.\r\n\r\nYou know how you can have a method that returns a <code>String</code> and assign the return value to a variable that you have declared an object? Now you can do that with a generic collection, too.\r\n\r\nIn general, the C# compiler makes assumptions about the generic type conversion. As long as you’re working up the chain for parameters or down the chain for return types, C# will just magically figure the type out.\r\n<h2 id=\"tab3\" >Covariance</h2>\r\nThe application now passes the list into the <code>MakeSchedule</code> method, but that method expects an enumerable collection of <code>Events</code>. Because parameters are covariant for generics now, it’s possible to pass in a <code>List</code> of <code>courses</code>, as <code>Course</code> is covariant to <code>Event</code>. This is covariance for parameters.","blurb":"","authors":[{"authorId":9109,"name":"John Paul Mueller","slug":"john-paul-mueller","description":"John Paul Mueller has written more than 100 books and more than 600 articles on topics ranging from functional programming techniques to application development using C++. ","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9109"}},{"authorId":9786,"name":"Bill Sempf","slug":"bill-sempf","description":"William Sempf is a technical and security architect. He serves as an adjunct faculty member at Columbus State Community College.","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9786"}},{"authorId":9787,"name":"Chuck Sphar","slug":"chuck-sphar","description":"Chuck Sphar was a full-time senior technical writer for the Visual C++ product group at Microsoft.","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9787"}}],"primaryCategoryTaxonomy":{"categoryId":33596,"title":"C#","slug":"csharp","_links":{"self":"https://dummies-api.dummies.com/v2/categories/33596"}},"secondaryCategoryTaxonomy":{"categoryId":0,"title":null,"slug":null,"_links":null},"tertiaryCategoryTaxonomy":{"categoryId":0,"title":null,"slug":null,"_links":null},"trendingArticles":null,"inThisArticle":[{"label":"Variance","target":"#tab1"},{"label":"Contravariance","target":"#tab2"},{"label":"Covariance","target":"#tab3"}],"relatedArticles":{"fromBook":[{"articleId":249507,"title":"Making Sure Your ASP.NET Site Is Accessible","slug":"making-sure-asp-net-site-accessible","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249507"}},{"articleId":249504,"title":"Employing Dynamic C# Programming Techniques","slug":"employing-dynamic-c-programming-techniques","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249504"}},{"articleId":249455,"title":"Using Structures as Records in C#","slug":"using-structures-records-c","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249455"}},{"articleId":249452,"title":"Dividing a Single C# Program into Multiple Assemblies","slug":"dividing-single-c-program-multiple-assemblies","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249452"}},{"articleId":249449,"title":"Using Anonymous Methods in C#","slug":"using-anonymous-methods-c","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249449"}}],"fromCategory":[{"articleId":289765,"title":"C# 10.0 All-in-One For Dummies Cheat Sheet","slug":"c-10-0-all-in-one-for-dummies-cheat-sheet","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/289765"}},{"articleId":249507,"title":"Making Sure Your ASP.NET Site Is Accessible","slug":"making-sure-asp-net-site-accessible","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249507"}},{"articleId":249504,"title":"Employing Dynamic C# Programming Techniques","slug":"employing-dynamic-c-programming-techniques","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249504"}},{"articleId":249455,"title":"Using Structures as Records in C#","slug":"using-structures-records-c","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249455"}},{"articleId":249452,"title":"Dividing a Single C# Program into Multiple Assemblies","slug":"dividing-single-c-program-multiple-assemblies","categoryList":["technology","programming-web-design","csharp"],"_links":{"self":"https://dummies-api.dummies.com/v2/articles/249452"}}]},"hasRelatedBookFromSearch":false,"relatedBook":{"bookId":281649,"slug":"c-7-0-all-in-one-for-dummies","isbn":"9781119428114","categoryList":["technology","programming-web-design","csharp"],"amazon":{"default":"https://www.amazon.com/gp/product/1119428114/ref=as_li_tl?ie=UTF8&tag=wiley01-20","ca":"https://www.amazon.ca/gp/product/1119428114/ref=as_li_tl?ie=UTF8&tag=wiley01-20","indigo_ca":"http://www.tkqlhce.com/click-9208661-13710633?url=https://www.chapters.indigo.ca/en-ca/books/product/1119428114-item.html&cjsku=978111945484","gb":"https://www.amazon.co.uk/gp/product/1119428114/ref=as_li_tl?ie=UTF8&tag=wiley01-20","de":"https://www.amazon.de/gp/product/1119428114/ref=as_li_tl?ie=UTF8&tag=wiley01-20"},"image":{"src":"https://www.dummies.com/wp-content/uploads/c-sharp-7.0-all-in-one-for-dummies-cover-9781119428114-203x255.jpg","width":203,"height":255},"title":"C# 7.0 All-in-One For Dummies","testBankPinActivationLink":"","bookOutOfPrint":false,"authorsInfo":"\n <p><b data-author-id=\"9109\">John Paul Mueller</b> is a writer on programming topics like AWS, Python, Java, HTML, CSS, and JavaScript. <b data-author-id=\"9786\">William Sempf</b> is a programmer and .NET evangelist. <b data-author-id=\"9787\">Chuck Sphar</b> was a full-time senior technical writer for the Visual C++ product group at Microsoft. </p>","authors":[{"authorId":9109,"name":"John Paul Mueller","slug":"john-paul-mueller","description":"John Paul Mueller has written more than 100 books and more than 600 articles on topics ranging from functional programming techniques to application development using C++. ","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9109"}},{"authorId":9786,"name":"Bill Sempf","slug":"bill-sempf","description":"William Sempf is a technical and security architect. He serves as an adjunct faculty member at Columbus State Community College.","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9786"}},{"authorId":9787,"name":"Chuck Sphar","slug":"chuck-sphar","description":"Chuck Sphar was a full-time senior technical writer for the Visual C++ product group at Microsoft.","_links":{"self":"https://dummies-api.dummies.com/v2/authors/9787"}}],"_links":{"self":"https://dummies-api.dummies.com/v2/books/"}},"collections":[],"articleAds":{"footerAd":"<div class=\"du-ad-region row\" id=\"article_page_adhesion_ad\"><div class=\"du-ad-unit col-md-12\" data-slot-id=\"article_page_adhesion_ad\" data-refreshed=\"false\" \r\n data-target = \"[{"key":"cat","values":["technology","programming-web-design","csharp"]},{"key":"isbn","values":["9781119428114"]}]\" id=\"du-slot-6217ba890c5cc\"></div></div>","rightAd":"<div class=\"du-ad-region row\" id=\"article_page_right_ad\"><div class=\"du-ad-unit col-md-12\" data-slot-id=\"article_page_right_ad\" data-refreshed=\"false\" \r\n data-target = \"[{"key":"cat","values":["technology","programming-web-design","csharp"]},{"key":"isbn","values":["9781119428114"]}]\" id=\"du-slot-6217ba890d11e\"></div></div>"},"articleType":{"articleType":"Articles","articleList":null,"content":null,"videoInfo":{"videoId":null,"name":null,"accountId":null,"playerId":null,"thumbnailUrl":null,"description":null,"uploadDate":null}},"sponsorship":{"sponsorshipPage":false,"backgroundImage":{"src":null,"width":0,"height":0},"brandingLine":"","brandingLink":"","brandingLogo":{"src":null,"width":0,"height":0}},"primaryLearningPath":"Advance","lifeExpectancy":null,"lifeExpectancySetFrom":null,"dummiesForKids":"no","sponsoredContent":"no","adInfo":"","adPairKey":[]},"status":"publish","visibility":"public","articleId":249359},"articleLoadedStatus":"success"},"listState":{"list":{},"objectTitle":"","status":"initial","pageType":null,"objectId":null,"page":1,"sortField":"time","sortOrder":1,"categoriesIds":[],"articleTypes":[],"filterData":{},"filterDataLoadedStatus":"initial","pageSize":10},"adsState":{"pageScripts":{"headers":{"timestamp":"2022-05-27T12:59:08+00:00"},"adsId":0,"data":{"scripts":[{"pages":["all"],"location":"header","script":"<!--Optimizely Script-->\r\n<script src=\"https://cdn.optimizely.com/js/10563184655.js\"></script>","enabled":false},{"pages":["all"],"location":"header","script":"<!-- comScore Tag -->\r\n<script>var _comscore = _comscore || [];_comscore.push({ c1: \"2\", c2: \"15097263\" });(function() {var s = document.createElement(\"script\"), el = document.getElementsByTagName(\"script\")[0]; s.async = true;s.src = (document.location.protocol == \"https:\" ? \"https://sb\" : \"http://b\") + \".scorecardresearch.com/beacon.js\";el.parentNode.insertBefore(s, el);})();</script><noscript><img src=\"https://sb.scorecardresearch.com/p?c1=2&c2=15097263&cv=2.0&cj=1\" /></noscript>\r\n<!-- / comScore Tag -->","enabled":true},{"pages":["all"],"location":"footer","script":"<!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->\r\n<script type='text/javascript'>\r\n(function(){var g=function(e,h,f,g){\r\nthis.get=function(a){for(var a=a+\"=\",c=document.cookie.split(\";\"),b=0,e=c.length;b<e;b++){for(var d=c[b];\" \"==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};\r\nthis.set=function(a,c){var b=\"\",b=new Date;b.setTime(b.getTime()+6048E5);b=\"; expires=\"+b.toGMTString();document.cookie=a+\"=\"+c+b+\"; path=/; \"};\r\nthis.check=function(){var a=this.get(f);if(a)a=a.split(\":\");else if(100!=e)\"v\"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(\":\"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case \"v\":return!1;case \"r\":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(\":\")),!c}return!0};\r\nthis.go=function(){if(this.check()){var a=document.createElement(\"script\");a.type=\"text/javascript\";a.src=g;document.body&&document.body.appendChild(a)}};\r\nthis.start=function(){var t=this;\"complete\"!==document.readyState?window.addEventListener?window.addEventListener(\"load\",function(){t.go()},!1):window.attachEvent&&window.attachEvent(\"onload\",function(){t.go()}):t.go()};};\r\ntry{(new g(100,\"r\",\"QSI_S_ZN_5o5yqpvMVjgDOuN\",\"https://zn5o5yqpvmvjgdoun-wiley.siteintercept.qualtrics.com/SIE/?Q_ZID=ZN_5o5yqpvMVjgDOuN\")).start()}catch(i){}})();\r\n</script><div id='ZN_5o5yqpvMVjgDOuN'><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>\r\n<!--END WEBSITE FEEDBACK SNIPPET-->","enabled":false},{"pages":["all"],"location":"header","script":"<!-- Hotjar Tracking Code for http://www.dummies.com -->\r\n<script>\r\n (function(h,o,t,j,a,r){\r\n h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\r\n h._hjSettings={hjid:257151,hjsv:6};\r\n a=o.getElementsByTagName('head')[0];\r\n r=o.createElement('script');r.async=1;\r\n r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\r\n a.appendChild(r);\r\n })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\r\n</script>","enabled":false},{"pages":["article"],"location":"header","script":"<!-- //Connect Container: dummies --> <script src=\"//get.s-onetag.com/bffe21a1-6bb8-4928-9449-7beadb468dae/tag.min.js\" async defer></script>","enabled":true},{"pages":["homepage"],"location":"header","script":"<meta name=\"facebook-domain-verification\" content=\"irk8y0irxf718trg3uwwuexg6xpva0\" />","enabled":true},{"pages":["homepage","article","category","search"],"location":"footer","script":"<!-- Facebook Pixel Code -->\r\n<noscript>\r\n<img height=\"1\" width=\"1\" src=\"https://www.facebook.com/tr?id=256338321977984&ev=PageView&noscript=1\"/>\r\n</noscript>\r\n<!-- End Facebook Pixel Code -->","enabled":true}]}},"pageScriptsLoadedStatus":"success"},"searchState":{"searchList":[],"searchStatus":"initial","relatedArticlesList":[],"relatedArticlesStatus":"initial"},"routeState":{"name":"Article3","path":"/article/technology/programming-web-design/csharp/revising-c-generics-249359/","hash":"","query":{},"params":{"category1":"technology","category2":"programming-web-design","category3":"csharp","article":"revising-c-generics-249359"},"fullPath":"/article/technology/programming-web-design/csharp/revising-c-generics-249359/","meta":{"routeType":"article","breadcrumbInfo":{"suffix":"Articles","baseRoute":"/category/articles"},"prerenderWithAsyncData":true},"from":{"name":null,"path":"/","hash":"","query":{},"params":{},"fullPath":"/","meta":{}}},"dropsState":{"submitEmailResponse":false,"status":"initial"},"sfmcState":{"newsletterSignupStatus":"initial"}}
The generics model implemented in C# 2.0 was incomplete. Generics are fine for making the programmer’s life easier, but they did little in that version to make the analyst’s life easier. It used to be very hard to model an actual business model using Generics, and that changed in C# 4.0. Although parameters in C# 2.0 all allowed for variance in several directions, generics did not.
Variance has to do with types of parameters and return values. Covariance means that an instance of a subclass can be used when an instance of a parent class is expected, while contravariance means that an instance of a superclass can be used when an instance of a subclass is expected. When neither is possible, it is called invariance.
All fourth-generation languages support some kind of variance. In C# 3.0 and earlier versions, parameters are covariant, and return types are contravariant. So, this works because string and integer parameters are covariant to object parameters:
public static void MessageToYou(object theMessage)
{
if (theMessage != null)
Console.Writeline(theMessage)
}
//then:
MessageToYou("It's a message, yay!");
MessageToYou(4+6.6);
And this works because object return types are contravariant to string and integer return types (for example):
object theMessage = MethodThatGetsTheMessage();
Generics are invariant in C# 2.0 and 3.0. This means that if Basket is of type Basket, those Baskets are not interchangeable as strings and objects are in the preceding example.
Variance
If you look at a method like the following one:
public static void WriteMessages()
{
List someMessages = new List();
someMessages.Add("The first message");
someMessages.Add("The second message");
MessagesToYou(someMessages);
}
and then you try to call that method with a string type
John Paul Mueller is a writer on programming topics like AWS, Python, Java, HTML, CSS, and JavaScript. William Sempf is a programmer and .NET evangelist. Chuck Sphar was a full-time senior technical writer for the Visual C++ product group at Microsoft.