Transfer from https://www.cnblogs.com/qixuejia/p/4383068.html
MSDN explains the following:
Covariant refers to the ability to use a more derived type than the original specified derived type.
"Contravariance" refers to the ability to use less derived types.
The explanation is correct, roughly the same, but not straightforward enough.
A straightforward understanding:
"Co-change", "Harmony Change", "very natural change"->string->object: covariant.
"Inverse", "inverse change", "abnormal changes"->object->string inversion.
Above is the individual understanding of covariance and contravariance, compared to remembering those derivation, type, original designation, larger, smaller words such as, personally think to be easy point.
Here's a joke:
Every day of one weeks should be read like this:
Monday = Busy day;
Tuesday = Death Day;
Wednesday = Not dead day;
Thursday = Dead Day;
Friday = Blessed day;
Saturday = Carefree Day;
Sunday = Injured Day
To demonstrate covariance and contravariance, and the difference between, create a console program Castudy, manually add two classes:
Because it's a demo, it's an empty class,
Just a little bit remember that dog inherits from Animal,
So dog becomes animal is the change of harmony (covariance), and if animal becomes dog it is abnormal change (inversion)
In the main function, enter:
Because dog inherits from animal, so animal aanimal = Adog; The Adog will be implicitly transformed into animal.
However, List<dog> does not inherit list<animal>, so the following prompt appears:
If you want to convert, you should use the following code:
list<animal> LstAnimal2 = Lstdogs.select (d = (Animal) d). ToList ();
You can see how complicated it is to turn a lstdogs into a lstanimal.
That's why Microsoft has added two new keywords: out,in, the following is their MSDN explanation:
The English of co-change is: "Covariant", the English of inversion is: "contravariant"
Why did Microsoft choose "Out" and "in" as attributes instead of them?
My personal understanding:
Because the English of covariance and contravariance is too complex, it does not reflect the difference between covariance and contravariance, but out and in is straightforward.
Out: Output (as a result), in: input (as parameter)
So if a generic parameter is marked as out, it is used for output and can only be returned as a result, and if a generic parameter is marked in, then it is used for input, that is, it can only be used as a parameter.
Currently the out and in keywords can only be used in interfaces and delegates, and the interfaces and delegates that Microsoft uses out and in tags are roughly as follows:
Let's take a look at the first ienumerable<t>.
As in the beginning, T is marked with out, so t represents the output, which is only returned as a result.
public static void Main ()
{
Dog Adog = new Dog ();
Animal aanimal = Adog;
list<dog> lstdogs = new list<dog> ();
list<animal> lstanimal = lstdogs;
list<animal> LstAnimal2 = Lstdogs.select (d = (Animal) d). ToList ();
ienumerable<dog> somedogs = new list<dog> ();
ienumerable<animal> someanimals = somedogs;
}
Because T can only do the result return, so T is not modified, the compiler can infer that the following statement is coerced into a valid, so
ienumerable<animal> someanimals = somedogs;
Can be checked by the compiler, the anti-compilation code is as follows:
Although the C # compiler's check is passed, IL does not know about covariance and contravariance, or it has to be a obediently cast.
Here I see this sentence:
ienumerable<animal> enumerable2 = (ienumerable<animal>) enumerable1;
Then is not can list<animal> LstAnimal3 = (list<animal>) lstdogs; It?
To answer this question you need to look back at the CLR via C # about generics and interfaces, and I won't explain.
The answer is no.
The above shows the covariance, and the next step is to demonstrate the inversion.
In order to demonstrate the inversion, it is necessary to find an in tag interface or a delegate, the simplest is:
In the main function, add:
action<animal> actionanimal = new Action<animal> (A + = {* Let animals be called */});
action<dog> Actiondog = Actionanimal;
Actiondog (Adog);
Obviously Actionanimal is let the animal call, because dog is animal, then since animal can call, dog certainly can also bark.
In keyword: contravariant, which represents input, is meant to be used only, not as a return value, so the C # compiler can infer from the in keyword that the generic type can only be used, so action<dog> actiondog = Actionanimal; Can be checked by the compiler.
Show the Out keyword again:
Add two classes:
public interface Imylist<out t>
{
T getelement ();
}
public class Mylist<t>: imylist<t>
{
Public T getelement ()
{
return default (T);
}
}
Because of the Out keyword, the following code can be compiled by
imylist<dog> mydogs = new mylist<dog> ();
imylist<animal> myanimals = mydogs;
Modify the above two classes to:
public interface Imylist<out t>
{
T getelement ();
void Changet (T t);
}
public class Mylist<t>: imylist<t>
{
Public T getelement ()
{
return default (T);
}
public void Changet (T t)
{
Change T
}
}
Compile:
Because T is modified by out, T can only be used as a parameter.
Also modify the two classes as follows:
public interface Imylist<in t>
{
T getelement ();
void Changet (T t);
}
public class Mylist<t>: imylist<t>
{
Public T getelement ()
{
return default (T);
}
public void Changet (T t)
{
Change T
}
}
This time use the In keyword.
Compile:
Because it is marked with the IN keyword, t can only be used, not as a return value.
The last modified code is:
public interface Imylist<in t>
{
void Changet (T t);
}
public class Mylist<t>: imylist<t>
{
public void Changet (T t)
{
Change T
}
}
The compilation was successful because in represents the inverse, so
imylist<animal> myanimals = new mylist<animal> ();
imylist<dog> mydogs = myanimals;
can be compiled successfully!.
In-depth understanding of C # Covariance and Contravariance