About covariance and contravariance from Object oriented inheritance. An inheritance relationship is a relationship between a subclass and a parent class, and a subclass inherits from the parent class, so the instance of the subclass is the instance of the parent class. For example animal is a parent class, dog is a subclass inherited from animal, and if the type of an object is dog, then he must be animal.
covariant inversion is the transformation of a delegate or generic interface between different parameter types or return value types using inheritance relationships. I admit that this is a very round, if you also think you might as well look down.
If a method accepts the dog parameter, then another method that accepts the animal parameter must also accept the parameter of the method, which is the animal transition to the dog direction is the inversion. If a method requires a return value of animal, then the method that returns dog must be able to satisfy its return value, which is the transformation of dog to animal direction is covariant.
The transition of a subclass to a parent is a covariant covariant used to return a value type with the Out keyword
The transformation from the parent class to the subclass is the inverse variable used in the parameter type of the method in keyword
The covariance in the covariant inversion is relative to the inheritance chain direction of the inheritance relation.
A Covariance of arrays:
Copy Code code as follows:
animal[] Animalarray = new dog[]{};
The preceding line of code is legal, the declared array data type is animal, and the dog array is given when the value is actually assigned; Each dog object can be safely converted to animal. The transformation of the dog approach to the animal is the transformation along the inheritance chain, so it is covariant.
Two. Covariance and Contravariance in a delegate
1. Covariance in a delegate
Copy Code code as follows:
The return value of the delegate definition is animal type is the parent class
Public delegate Animal Getanimal ();
The return value in the delegate method implementation is dog, which is a subclass
Static Dog Getdog () {return new Dog ();}
The return value of the Getdog is dog, dog is a subclass of animal; Returning a dog is equivalent to returning a animal; therefore, the following assignment to the delegate is valid
Getanimal GetMethod = Getdog;
2. Contravariance in a delegate
Copy Code code as follows:
The definition parameter type in the delegate is dog
public delegate void Feeddog (Dog target);
The parameter type in the actual method is animal
static void Feedanimal (Animal target) {}
Feedanimal is an effective method of Feeddog delegates, because the type of argument accepted by the delegate is dog, and the parameter Feedanimal accepts is that Animal,dog can be implicitly converted to animal, so delegates can do type conversions safely, Correct implementation of the delegation method;
Feeddog Feeddogmethod = Feedanimal;
The parameters that define the delegate are subclasses, and in fact the arguments to the delegate method are the broader parent class animal, the parent class changing to the subclass, and the contravariant
Three. Covariance and contravariance of generic delegates:
1. Contravariance in a generic delegate
The following delegate declares:
Copy Code code as follows:
public delegate void Feed<in t> (T target);
The feed delegate accepts a generic type T, noting that there is an in keyword in the angle bracket of the generic, which is the function of telling the compiler that type T may have to be contravariant when assigning a value to the delegate
Copy Code code as follows:
Declare a delegate of T to Animal first
feed<animal> Feedanimalmethod = A=>console.writeline ("Feed Animal Lambda");
Assigning T to a delegate of animal to T is a dog delegate variable, which is legal because there is an in keyword when defining a generic delegate, and if the in keyword is removed, the compiler considers it illegal
feed<dog> Feeddogmethod = Feedanimalmethod;
2. Covariance in generic delegates
The following delegate declares:
Copy Code code as follows:
Public delegate T Find<out t> ();
Find delegate to return an instance of a generic type T, there is an out keyword in the angle bracket of the generic, which indicates that the T type is likely to be covariant
Copy Code code as follows:
Declaring find<dog> delegates
Find<dog> Finddog = () =>new Dog ();
Declaring find<animal> delegates and assigning Finddog to Findanimal is legal, and type T changes from dog to Animal is covariant
find<animal> findanimal = Finddog;
Four. Covariance and contravariance in a generic interface:
Covariant contravariance in a generic interface is very similar to a generic delegate, except that the angle bracket portion of a generic definition is swapped to the definition of an interface.
1. Contravariance in a generic interface
The following interface definitions:
Copy Code code as follows:
public interface Ifeedable<in t>
{
void Feed (T-t);
}
Interface Generic T has an in keyword prior to indicating that the generic interface may have to be contravariant
For example, the generic type is Feedimp<t>, and the above generic interface is implemented; It is important to note that covariant and contravariant keyword In,out cannot be used in generic classes and the compiler does not allow
Copy Code code as follows:
public class Feedimp<t>:ifeedable<t>
{
public void Feed (T-t) {
Console.WriteLine ("Feed Animal");
}
}
Look at an example of using interface contravariance:
Copy Code code as follows:
ifeedable<dog> Feeddog = new feedimp<animal> ();
The code above assigns the feedimp<animal> type to the ifeedable<dog> variable; Animal to Dog, so it's a reversal.
2. Covariance in a generic interface
The definition of the following interface:
Copy Code code as follows:
public interface Ifinder<out t>
{
T find ();
}
Generic t of a generic interface is preceded by an out keyword to illustrate that this interface is likely to be covariant; The following generic interface implementation class
Copy Code code as follows:
public class finder<t>:ifinder<t> where T:new ()
{
Public T Find () {
return new T ();
}
}
With covariance, the generic type of Ifinder is animal, but because there are out keywords, I can assign finder<dog> to it
ifinder<animal> finder = new finder<dog> ();
The concept of covariance and contravariance is not easy to understand and can be thought through in real code. What's the use of such a winding? The answer is yes, it's better to reuse code through covariance and contravariance. Reuse is an eternal pursuit of software development.