Covarience And ContraVariance

19144 ワード

  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