Covarience And ContraVariance
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 5 namespace CovarientAndContraVarient 6 { 7 class Program 8 { 9 static object GetObject() { return null; } 10 static void SetObject(object obj) { } 11 12 static string GetString() { return ""; } 13 static void SetString(string str) { } 14 15 static void Main(string[] args) 16 { 17 Func<object> getString = GetString; 18 19 Action<string> setString = SetObject; 20 21 Func<string> getString1 = GetString; 22 23 //1. Delegate variable implicitly cast is not valid until .net 4.0 24 Func<object> setString2 = getString1; 25 26 //Assignment compatibility, 27 IEnumerable<String> test = new List<string>(); 28 29 //covariance OUT == > Covariance 30 IEnumerable<object> test1 = new List<string>(); 31 32 //Assignment compatibility 33 Action<Object> objAction = StaticMethod; 34 35 //ContraConvariance , IN === > ContraConvariance 36 Action<String> stringAction = StaticMethod; 37 38 //2. Array Covariance, support in C# 1.0 39 object[] objArray = new String[] { "a", "b", "c" }; 40 41 //Covariance in array is not safe, below code will throw exception 42 objArray[0] = 5; 43 44 //3. Co/contra- Variance don't support value type, below code is invalid 45 //IEnumerable<object> objects = new List<int>(); 46 47 //you can use an interface instance that has methods with more 48 //derived return types than originally specified (covariance--OUT) 49 //or that has methods with less derived parameter types (contravariance--IN). 50 51 //Contravariance 52 IMyTest<FileStream> myTestInstance = new MyTestClass1<Stream>(); 53 54 IMyTest<Stream> myTest = new MyTestClass1<Stream>(); 55 56 //covariance 57 IMyTest1<object> myTest1Instance = new MyTestClass2<string>(); 58 59 IMyTest<FileStream> myTestInstance1 = myTest; 60 61 //Below Code, you will think it is a little strange, but absolutely it works well!!!!!!!!! 62 //4. You can mark a generic type parameter as covariant if it is used only as a method return 63 //type and is not used as a type of formal method parameters. 64 //5. And vice versa, you can mark a type as contravariant if it is used only as a type of 65 //formal method parameters and not used as a method return type. 66 IMyFirstTestClass<object, string> testClass = null; 67 IMyFirstTestClass<string, object> testClass1 = testClass; 68 } 69 70 public static void StaticMethod(object o) 71 { 72 } 73 } 74 75 public interface IMyFirstTestClass<in T1, out T2> 76 { 77 T2 DoSomething(T1 para); 78 } 79 80 81 82 //6. Variant type only can declared in interfaces and delegates only!!!!!!! 83 //public class MyTestClass<in T> 84 //{ 85 86 //} 87 88 //Contravariance 89 public interface IMyTest<in T> 90 { 91 void PrintTest(T param); 92 } 93 94 //7. Below code, T is invariance, if you want to it be Contravariance, you must declare it explicitly. 95 //Same as covariance 96 public interface IMyTestExtend<T> : IMyTest<T> 97 { 98 } 99 100 public class MyTestClass1<T> : IMyTest<T> 101 { 102 public void PrintTest(T para) 103 { 104 Console.WriteLine("This is " + typeof(T) + " PrintTest Method!"); 105 } 106 } 107 108 //Covariance 109 public interface IMyTest1<out T> 110 { 111 T PrintTest(); 112 } 113 114 public class MyTestClass2<T> : IMyTest1<T> 115 { 116 public T PrintTest() 117 { 118 Console.WriteLine("This is " + typeof(T) + " PrintTest Method!"); 119 return default(T); 120 } 121 } 122 123 public delegate void MyHander<in T>(T para); 124 125 //Below method declaration is invalid, because 'in' is contravariance, it only can be in paramter type 126 //public delegate T MyHander1<in T>(T para); 127 128 public delegate T MyHandler2<out T>(object para); 129 130 //Below method declaration is invalid, because 'out' is covariance, it only can be in returned type 131 //public delegate void MyHandler2<out T>(T para); 132 133 }
FYI: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx