According to the rules of variability, only interfaces and delegates can mark variability. You can take advantage of variability only if the type parameter is a reference type.
Invariance: The parameters of a generic type cannot be changed, which means that when an object of type myinterface<string> is created, only the myinterface<string> type is assigned to it
1 namespacecontravariantandcovariant2 {3 Public InterfaceMyinterface<t>//no variability is specified, indicating that the type parameter of this interface is constant4 {5 voidShow (t t);6 }7 8 Public classShowobject:myinterface<object>9 {Ten Public voidShow (Objectt) One { A Console.WriteLine (t.tostring ()); - } - } the - Public classShowstring:myinterface<string> - { - Public voidShow (stringt) + { - Console.WriteLine (t); + } A } at - Public classShowint:myinterface<int32> - { - Public voidShow (intt) - { - Console.WriteLine (t.tostring ()); in } - } to + class Program - { the Static voidMain (string[] args) * { $ //correctPanax NotoginsengMyinterface<string> str_invariant =NewShowstring ();//only myinterface<string> types can be assigned - //Error theMyinterface<string> str_contravariant =NewShowobject ();//when assigning other types, the compiler will error + //CS0266 cannot implicitly convert type "Contravariantandcovariant.showobject" to "contravariantandcovariant.myinterface<string > ". An explicit conversion exists (is there a missing cast?) A the } + } - $}
Inverse degeneration: A generic type parameter can be changed from a class to its derived class, for example: You can convert myinterface<object> to myinterface<string>. Contravariance is represented by in, because it appears in the input position (the parameter of the method), in is the meaning to go in.
1 namespacecontravariantandcovariant2 {3 Public Interfacemyinterface<inchT>//specify the inverse of T with the in keyword4 {5 voidShow (t t);//t is a parameter type6 }7 8 Public classShowobject:myinterface<object>9 {Ten Public voidShow (Objectt) One { A Console.WriteLine (t.tostring ()); - } - } the - Public classShowstring:myinterface<string> - { - Public voidShow (stringt) + { - Console.WriteLine (t); + } A } at - Public classShowint:myinterface<int32> - { - Public voidShow (intt) - { - Console.WriteLine (t.tostring ()); in } - } to + class Program - { the Static voidMain (string[] args) * { $myinterface<Object> obj =NULL;Panax Notoginsengmyinterface<string> str = obj;//You can convert the myinterface<object> type to the myinterface<string> type - } the } + A}
Covariance: Generic type parameters can be changed from one class to its base class, for example: You can convert myinterface<string> to myinterface<object>. Contravariant is expressed as out, because it appears in the output position (method return value), out is the meaning.
1 namespacecontravariantandcovariant2 {3 Public Interfacemyinterface< outT>//specifying the covariance of T with the Out keyword4 {5T Show ();//T is the return type6 }7 8 Public classShowobject:myinterface<object>9 {Ten Public ObjectShow () One { A return NULL; - } - } the - Public classShowstring:myinterface<string> - { - Public stringShow () + { - return NULL; + } A } at - class Program - { - Static voidMain (string[] args) - { - //Error in //myinterface<object> obj = null; - //myinterface<string> str = obj;//cannot convert myinterface<object> type to myinterface<string> type to + //correct -myinterface<string> str =NULL; themyinterface<Object> obj = str;//You can convert the myinterface<string> type to the myinterface<object> type * } $ }Panax Notoginseng}
The CLR is to ensure that the conversion of a type is secure, and covariance is well understood that subclasses can be converted to a parent class because all members of the parent class object are included in the child class object. This conversion is safe.
But in the case of contravariance, it is unsafe for the parent class to be converted to subclasses, and no members of the child class are in the parent object when the Richter scale cannot be converted.
In fact, there is a misunderstanding, that is, about references and objects. When contravariant, such as in the code of the above inversion:
Myinterface<object> obj = null;
myinterface<string> str = obj;
Str. Show ("123")
STR is a variable of type myinterface<string>, but it refers to an object of type myinterface<object>, so when we call the show () method, it is actually obj. Show ();
The arguments to obj are of type object, we pass in a string type, and string---->object is safe to convert. So the inverter is safe!
In the same vein, covariance:
myinterface<string> str = NULL;
myinterface<object> obj = str;
Object result = Obj.show ();
You can see that obj is a variable of type myinterface<object>, but the object it refers to is the myinterface<string> type, so when we call the show () method, it is actually str. Show (),
It returns a string type, but obj. Show () Returns an object type, so we use a variable of type object to receive the return value and eventually become a string----->object type conversion, so the covariance is safe.
The understanding of C # contravariance and covariance-----Why contravariance can convert type arguments of type object to type parameters of type string