This article is mainly for you to introduce in detail the C # inverter and covariance related data, with a certain reference value, interested in small partners can refer to
More delegate delegate and lambda expressions are used in this article, and if you're not familiar with them, check out my article delegate and anonymous delegates, anonymous delegates and lambda expressions to help you build a complete knowledge system.
In the process of C # from birth to development and growth, new knowledge points are constantly introduced. Contravariance and covariance are not original C #, but are subsequently introduced. In Java there are also contravariance and covariance, follow-up I will also write a Java inverter covariance article, interested friends can pay attention to.
Inversion and co-change, sounds very abstract, advanced, in fact, very simple. Look at the following code:
Class Person {} class Student:person {} class Teacher:person {} class program { static void Main (string[] ar GS) { list<person> plist = new list<person> (); plist = new list<student> (); plist = new list<teacher> ();}}
In the above code, plist = new list<student> (), plist = new list<teacher> () produces a compilation error. Although the person is the parent of Student/teacher, but the list<person> type is not the parent class of the list<student/teacher> type, the above assignment statement type conversion failed incorrectly.
As such, the assignment is not allowed before C # 4.0, and type safety is the primary factor as to why it is not allowed. Look at the following sample code:
list<person> plist = new list<student> ();p List. ADD (New Person ());p list. ADD (New Student ());p list. ADD (New Teacher ());
The following example assumes that list<person> plist = new List<student> () allows assignment, that plist although the type is list<person> set, the actual point is list< Student> collection. Plist. Add (new Person ()), the addition operation is actually called List<student>. ADD (). The person type cannot be safely converted to student, so the set definition does not make sense, so the assumptions above are not true.
But the situation changed after C # 4.0, not " something impossible ", but a new adjustment to the flexibility of the application. The same program as in C # 4.0 is still not allowed, but there are exceptions. Starting with C # 4.0, in generic delegates, generic interfaces, special cases are allowed to occur (essentially, no special changes have occurred, as explained later). The following example:
delegate void Work<t> (T item); Class person{public string Name {get; set;}} Class student:person{public string like {get; set;}} Class teacher:person{Public string Teach {get; set;}} Class program{ static void Main (string[] args) { work<person> worker = (p) + = {Console.WriteLine (P . Name); }; ; Work<student> Student_worker = (s) + = {Console.WriteLine (s.like);}; Student_worker = worker; Compile error here }}
According to the previous theoretical support, Student_worker = worker, the error is easy to understand. But the purpose of our program here is to let Woker act as work<student> function, and later calls Student_worker (s) actually call Woker (s). In order to meet our needs, the process needs to be handled in 2 ways:
1, because in the call Student_worker (s), the actual execution is Woker (s), so the type of s variable is required to successfully convert to Woker required parameter type.
2. You need to tell the compiler that it allows you to assign an object of type work<person> to a variable of type work<student>.
Condition 1 when Student_worker () is called, the compiler prompts the requirement that the parameter must be an student type object that can be successfully converted to the person type object.
Condition 2 requires an adjustment to the woke delegate definition, which is adjusted as follows:
delegate void Workin<in t> (T item);
Change the name of the delegate to Workin is for but do not modify before and after the delegate, the key point is <in t>. By adding the In keyword, label the generic delegate's type parameter T, which is used only as a parameter to the delegate method. At this point the program above is compiled and executed successfully.
delegate void Workin<in t> (T Item), class program { static void Main (string[] args) { Workin<person > Woker = (p) = = {Console.WriteLine (p.name);}; workin<student> student_worker = Woker; Student_worker (new Student () {name= "Tom", like= "C #"}); }
For the requirement that the type parameter be a subtype, the value of the assignment type argument to the parent type is called the inverse of the variable. Contravariant in C # requires the type parameter of the generic in the in dimension. Contravariance is called contravariance, but it is only the form of a parent object that is assigned to a subclass variable, which is essentially the type conversion of the parameter when the method is called. Student s = new Person (), which is not possible, this is not contravariant is wrong.
The above code as you can convert to the following form, then you can forget the inversion, the essence is more important than the phenomenon