Variants (covariance and contravariance)

Source: Internet
Author: User

The introduction of variants is to increase the flexibility of generics by making it possible for a variable of a generic type to be converted to a type for compatibility when assigned. Let's look at an example:

public delegate void Dowork<t> (T arg);

........

Dowork<a> del1=delegate (A arg) {//...};

Dowork<b> Del2=del1;

b bb=new B ();

Del2 (BB);

Where A, B is two classes, Class B inherits Class A, that is: public class a{...} public class b:a{...}

The above code could not compile successfully because the type could not complete the conversion. To solve this problem, a variant is introduced.

(1) Covariance and contravariance

Variants can be divided into covariance and contravariance, whether covariant or contravariant, from the name can be seen in the difference because it is in the direction of conversion.

For covariance and Contravariance, 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.

Of course, this has been explained very clearly, the following on my personal view to explain.

Let us look at the example above, if we make the following changes:

public delegate void Dowork<in t> (T Arg);

........

Dowork<a> del1=delegate (A arg) {//...};

Dowork<b> Del2=del1;

b bb=new B ();

Del2 (BB);

After the code is modified, the above code can be compiled. In fact, this example belongs to the inverse, the example of the conversion direction of the generic delegate variable and the type of implicit conversion direction in the form of "inverse", the opposite direction, it is called "inversion."

Of course, covariant appetite inversion is relative, covariant in the form of a generic interface or generic delegate variable in the direction of assignment and the implicit conversion direction of the type. Let's take a look at the covariance example:

Defining types

public class a{}

public class b:a{}

Generic interface

public interface Itest<out t>

{

T Create ();

}

Implementing interfaces

public class test<y>:itest<y> where Y:new ()

{

Public Y Create ()

{

return new Y ();

}

The following code-assignment conversions

Itest<b> t1=new test<b> ();

Itest<a> t2=t1;//Assignment succeeded

A a=t2.create ();

Console.WriteLine (A.gettype (). Name);

}

In the example above, Itest<b>->itest<a>, however, since type B is derived from type A, it can be implicitly converted to a variable of type A, so the direction of assignment of the generic variable is consistent with the implicit conversion direction of the type specified by the type parameter, which is the " Co-change ".

Of course, variants support only generic interfaces and delegates, and variants cannot be used for classes and structs.

(2) input and output of type parameters

Through the introduction of covariance and contravariance, it is known that generic definitions can use variants by adding an in or out modifier for the type parameter. Types that are decorated with the in modifier can be interpreted as input types, which can only be used as input parameters, and an out modifier to represent the type as an output type, typically used for the return value of a method.

Let's look at an example that uses out:

`1 usingSystem;2 usingSystem.Collections.Generic;3 usingSystem.Linq;4 usingSystem.Text;5 usingSystem.Threading.Tasks;6 7 namespaceMy8 {9     #regionDefining classesTen      Public classBase {} One      Public classtest:base {} A     #endregion -  -     #regionDefining delegates the      Public DelegateT mydelegate< outT>(); -     #endregion -  -     class Program +     { -         Static voidMain (string[] args) +         { Amydelegate<test> D1 =Delegate() at             { -                 return NewTest (); -};//using anonymous Methods -  -             //then define a mydelegate delegate, type base -Mydelegate<base> D2 =D1; in             //Test Call delegate variable D2 -Base B =D2 (); to             //True type of output variable B +Console.Write ("type of variable B: {0}", B.gettype (). Name); -  the Console.read (); *         } \$     }Panax Notoginseng}`

In the example, the implicit conversion of a type is consistent with the assignment of a delegate variable, so the variant of this instance is covariant.

The output type parameter is given above, then we look at the input type parameter, the code is as follows:

`1 usingSystem;2 usingSystem.Collections.Generic;3 usingSystem.Linq;4 usingSystem.Text;5 usingSystem.Threading.Tasks;6 7 namespaceMy8 {9     #regionDefining typesTen      Public Abstract classWorkbase One     { A          Public Abstract voidRun (); -     } -      Public classFinancemng:workbase the     { -          Public Override voidRun () -         { -Console.WriteLine ("Financial Management"); +         } -     } +      Public classPaymentmng:workbase A     { at          Public Override voidRun () -         { -Console.WriteLine ("Compensation Management"); -         } -     } -      Public classJobanalymng:workbase in     { -          Public Override voidRun () to         { +Console.WriteLine ("Job Analysis"); -         } the     } *     #endregion \$ Panax Notoginseng     #regionGeneric interface -      Public Interfaceiwork<inchW> the     { +         voidDoWork (w w); A     } the  +     //implementing a generic interface -      Public classMywork<t>: iwork<t>whereT:workbase \$     { \$          Public voidDoWork (T W) -         { - W.run (); the         } -     }Wuyi     #endregion the  -     class Program Wu     { -         Static voidMain (string[] args) About         { \$Iwork<workbase> everywork =NewMywork<workbase>(); -  -             //Call a -Iwork<financemng> Work1 =everywork; AWork1. DoWork (Newfinancemng ()); +  the             //Call Two -Iwork<paymentmng> WORK2 =everywork; \$Work2. DoWork (Newpaymentmng ()); the  the             //call three theIwork<jobanalymng> Work3 =everywork; theWork3. DoWork (Newjobanalymng ()); -  in Console.read (); the         } the     } About}`

In this case, the direction of the assignment is reversed in the direction of the implicit conversion of the type.

From the previous example, you can draw a rule that the input type parameter (using the in modifier) is contravariant, and the output type parameter (using the Out modifier) is covariant ....

Variants (covariance and contravariance)

Related Keywords:

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.