C # general discussion-variants (covariant/inverter)

Source: Internet
Author: User

There are four classes.

          

 

    =;

This assignment is certainly okay, but it's justPolymorphism.

The general meaning of the variant is: there are two types of T and U, and T = U (here the equal sign isAssignmentIf T and U get t' and U' after some operation, and T' = U' is also trueOperationIs a covariant. If U' = t', this operation is called an inverter.


T = ↓Operation(T) = Operation(U);


T = U;= Operation2(T);
I. Special covariant-array

We often say that the concept of covariance and inversion is introduced in. net 4.0, but it is not actually. As long as it complies with the above definition, it is a variant. Let's first look at a covariant included in. net 1.0:

    Animal[] animalArray =  Dog[];

ThisNoPolymorphism, because the parent class of Dog [] is not Animal [], but an object.
Let's take a look at the definition of variants. First, Animal = Dog. This is true, because Dog is a subclass of Animal. Then, after the Array operation, the left and right sides of the equation are Animal [] and dog [], and the equation is still true. This is the definition of the Football Association.

Some may be confused. Why is the equal sign set up?
We need to make it clear that the C # Language specifies that the Array operation is a covariant and Compiler supports it, so the equation is true. Variants are set by humans. You can even specify that any operation is a covariant or an inverter. This is nothing more than making the value assignment at the compilation and runtime variants pass.

Let's take a look at the application of Array:

    Animal[] animalArray =  Dog[    animalArray[] =  Bird(); 

The above code can be compiled, and the Line1 code can also run, but an exception will be thrown at Line2. Therefore, although the Array operation is a covariant, it is not safe, in some cases, errors may occur.

As to why we need to support covariant like Array, according to Eric Lippert in Covariance and Contravariance in C #, Part Two: Array Covariance, it is to be compatible with Java syntax, although he is not very satisfied with this design.

 

Ii. Variations in Delegation

In. net 2.0, delegation also supports covariant, but currently only supports method assignment.

Consider the following code

              OnAnimalCatched(Animal animal) {}       OnDogCatched(Dog dog) {}  = OnDogCatched;     catchDog = OnAnimalCatched;  

Similarly, the following is a covariant.

            Animal CatchAnAnimal() {   Animal(); }     Dog CatchADog() {   Dog(); } = CatchAnAnimal;     animalCatching = CatchADog; 

 

For Action <T> and Func <TResult> (.. net 3.5. The following example reports an error during compilation.

    Action<Animal> aa = animal =><Dog> ad = aa;  

 

Iii. Variants in generics

Most of the changes we often talk about are the variants introduced in. net 4.0 for generic delegation and generic interfaces.

Generic Delegation

We found that when it reaches. net 4.0, the code that cannot be compiled has passed

    Action<Animal> aa = animal =><Dog> ad = aa;  

 

In fact, the signature of the Action has changed, and the keyword "in" is added.

       Action<T>(T obj);        Action< T>(T obj); 

 

Similarly, the signature of Func has changed and the out keyword is added.

      TResult Func<TResult>();       TResult Func< TResult>(); 

In and out are the keywords used in C #4.0 to explicitly represent the covariant and inverter in generics. In indicates the inverter parameter, and out indicates the covariant parameter.

For the variant of generic delegation,. net 4.0 is mainly enhanced compared with the previous version.Delegate instance assignment delegate instance(The method assigned to the delegated instance is supported by. net 2.0 ).

Generic Interface

Before. net 4.0, Array was covariant (although not secure), but IList <T> was not, and IEnumerable <T> was not. In. net 4.0, we can finally do this:

    IEnumerable<Animal> animals =  List<Dog>();  

 

However, the following operations may cause compilation failure:

    <Animal> a2 =  List<Dog>(); 

 

The reason is, of course, because <T> in. net 4.0 is covariant, and IList <T> is not:

      IEnumerable< T>  IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable

 

Since generic interfaces have been changed collaboratively, they also have inverters, such as <T>.

 

4. Some questions

1. Q: Can I add the in/out keyword to the custom generic interface and the generic delegate to indicate that it is inverter or covariant?

A: Of course this is impossible. The compiler will verify it.

In general, if all methods that use T in a generic interface only use T for input parameters, T can be an inverter parameter. If T is used, T can be a covariant parameter.

Delegated.

2. Q: Since in/out cannot be garbled, why? Is it impossible for the compiler to determine the value of the covariant or inverter?

A: This theory should be acceptable. However, the in/out keyword is like a contract between a generic delegate and a generic interface definer and the user. You must explicitly specify the usage method, otherwise, some codes in the program that are neither polymorphism nor marked as covariant or inverter, but can be assigned successfully seem messy.

3. Q: Is it true that all generic delegation and interfaces comply with the changing rules of input parameters while output parameters are invert?

A: We define a generic delegate Operate. Its input parameter is an Action.

  Operate<T>(Action<T> action);

Action <Mammal> MammalEat = mammal => Console. writeLine (<Panda> PandaEat = panda => Operate <Mammal> MammalOperation = action => action (Dog (); this is allowed.

Then we can perform the following operations

    
MammalOperation(MammalEat);

If we want this generic delegate to be a variant, T is used as the input parameter as we usually understand, it must be an inverter, And the in keyword should be added. We do not consider the prompts of the compiler. Suppose it is defined as follows:

      Operate< T>(Action<T> action);

Because it is an inverter, we can assign Operate <Mammal> to Operate <Panda>

    Operate<Panda> PandaOperate = MammalOperation;

Since the Operate T has been changed to Panda, the T of the corresponding parameter Action should also be changed to Panda, so the above "Operation 1" can be changed to this:

        MammalOperation(PandaEat);

Eventually it becomes PandaOperate = (new Dog ())

 

    Operate<Animal> AnimalOperate = MammalOperation;

 

The above example shows that not all input parameters are inverter? In fact, this is not completely an input parameter. Because of the impact of Action <T>, it seems that it has become "inverse Inverse association "? If you replace Action <T> with Func <T>, Operate <T> should use the in keyword. Isn't it a charge? Fortunately, this situation is rarely encountered at work, let alone the compiler checks for us.

 

For the above content, refer to the Covariance and Contravariance In C # series from Eric Lippert and provide a detailed description of the evolution of the. net covariant inverter. If you are interested, please take a look.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.