Last active
February 7, 2017 01:57
-
-
Save waf/b39e3c71bab1198d8d7603c66675ec66 to your computer and use it in GitHub Desktop.
Covariance and Contravariance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Collections.Generic; | |
public class Program | |
{ | |
public void Main(string[] args) | |
{ | |
Apple apple = new Apple(); | |
Orange orange = new Orange(); | |
Fruit fruit = new Apple(); | |
// covariance (out) | |
// VALID - data only comes "out" of IEnumerable<out T> | |
{ | |
IEnumerable<Fruit> fruitEnumerable = new List<Apple> { apple }; | |
Fruit first = fruitEnumerable.First(); // fine if it's an apple! | |
} | |
// contravariance (in) | |
// VALID - data only goes "in" to the parameter of Func<in T, out TResult> | |
{ | |
Func<Apple, object> appleFunction = (appleParam) => appleParam.MakeAppleJuice() ?? appleParam.Eat(); | |
Func<Fruit, object> fruitFunction = (fruitParam) => fruitParam.Eat(); | |
appleFunction = fruitFunction; | |
appleFunction(apple); // ok because fruitFunction works on apples | |
} | |
// covariance (out) | |
// COMPILE ERROR - not logical! Data can go in and come out of IList<T> (.Add and .First). | |
{ | |
IList<Fruit> fruitList = new List<Apple>(); | |
fruitList.Add(new Orange()); // adding an orange, when the underlying collection only suppots apples! | |
} | |
// contravariance (in) | |
// COMPILE ERROR - not logical! Data can come out of the Func<in T, out TResult> as return values. | |
{ | |
Func<object, Apple> appleFunction = (_) => apple; | |
Func<object, Fruit> fruitFunction = (_) => orange; | |
appleFunction(apple); | |
fruitFunction(fruit); | |
// BOOM | |
appleFunction = fruitFunction; | |
Apple appleReturn = appleFunction(null); // oh no an Orange! | |
} | |
} | |
public abstract class Fruit | |
{ | |
public object Eat() => null; | |
} | |
public class Apple : Fruit | |
{ | |
public object MakeAppleJuice() => null; | |
} | |
public class Orange : Fruit | |
{ | |
public object MakeOrangeJuice() => null; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment