Covariance and contravariance of generics

Source: Internet
Author: User

1. Types of variability: covariance and contravariance

Variability is the use of one object as another object in a type-safe manner. If you cannot replace one type with another, then this type is called: invariants . Covariance and contravariance are two opposing concepts:

    • If a returned type can be replaced by its derived type, then this type is the one that supports covariant
    • If a parameter type can be replaced by its base class, then this type is supported for contravariance .
2. C # 4.0 support for generic variability

Before C # 4.0, all generic types were invariants -that is, replacing one generic type with another, even if they had an inheritance relationship, in short, the generics before C # 4.0 did not support covariance and contravariance.

C # 4.0 out in uses generics in a covariant and contravariant manner, with two keywords: and.

Let's take a look at the code that takes advantage of the covariant type parameter:

public class BaseClass{    //...}public class DerivedClass : BaseClass{    //...}

Below we use covariant type parameters to perform allocations similar to ordinary polymorphism:

IEnumerable<DerivedClass> d = new List<DerivedClass>();IEnumerable<BaseClass> b = d;

In the above instance, before C # 4.0, it was not compiled properly, except for a cast of the subclass collection when assigned to the base class collection, but still throws a type cast exception at run time.

Let's look at an example code for contravariance:

b = (target) => { Console.WriteLine(target.GetType().Name); };Action<DerivedClass> d = b;d(new DerivedClass());

In the example above, the Action<BaseClass> delegate of our type is assigned to a variable of type Action<DerivedClass> , and according to the definition of the contravariant we can know that the Action<T> type is supported for contravariance.

Why IEnumerable<T> and what Action<T> types of contravariance and covariance can be supported separately? Let's look at the definitions of these two types in. NET:

//IEnumerable<T> 接口的定义(支持协变)public interface IEnumerable<out T> : IEnumerable//Action<T> 委托的定义(支持逆变)public delegate void Action<in T>(T obj);

To ensure type safety, the C # compiler out in adds some restrictions to generic parameters that use the and keywords:

    • Type parameters that support covariant ( out ) can only be used in the output location: function return value, property's get accessor, and some location of the delegate parameter
    • Type parameters that support contravariant ( in ) can only be used in the input location: The method parameter or some position of the delegate parameter.
3. Limitations of generic variability in C #

1. Variability of type parameters that do not support classes

Only interfaces and delegates can have variable type parameters. inand out modifiers can only be used to decorate generic interfaces and generic delegates.

2. Immutability only supports reference conversions

Immutability can only be used for reference types, prohibit any value types and user-defined conversions, as the following conversions are not valid:

    • IEnumerable<int>Convert to IEnumerable<object> --boxing conversion
    • IEnumerable<short>Convert to IEnumerable<int> --value type conversion
    • IEnumerable<string>Convert to IEnumerable<XName> --user-defined conversions

3. Type parameters are used out or ref will prohibit variability

For a generic type parameter, if you want to pass the argument of that type to out a ref method that uses or a keyword, you do not allow variability, such as:

void someDelegate<in T>(ref T t)

This code compiler will make an error.

4. The variability must be explicitly specified

From the implementation of the compiler can fully determine which generic parameters can be contravariant and covariant, but actually did not do so, because the C # development team believes that:

Variability must be explicitly specified by the developer, as it will encourage developers to think about the consequences of their actions and to consider whether their designs are reasonable.

5. Notice disruptive modifications

There is a risk of breaking the current code when modifying the variability of an existing code interface. For example, if you rely on the result of an IS or as operator that does not allow variability, the behavior of the code will be different when running at. NET 4 o'clock. Similarly, in some cases, overload resolution chooses different methods because there are more options available. Therefore, sufficient unit testing and defensive measures should be done to introduce variability into existing code.

6. Multicast delegation and variability can not be mixed

The following code can be compiled, but throws an exception at run time ArgumentException :

stringFunc = () => "";Func<object> objectFunc = () => new object();Func<object> combined = objectFunc + stringFunc;

This is because the method that is responsible for linking multiple delegates requires that the Delegate.Combine parameters must be of the same type. The above example can be modified to the correct code as follows:

Func<string> stringFunc = () => "";Func<object> defensiveCopy = new Func<object>(stringFunc);Func<object> objectFunc = () => new object();Func<object> combined = objectFunc + defensiveCopy;
Reference & Extended Reading

Covariance and Contravariance
Covariance and Contravariance in generics
Covariance and Contravariance in delegates
"In-depth understanding of C #": 13.3 generic variability of interfaces and delegates
"Effective C #": Entry 29: Support for generic covariance and contravariance
CLR via C #: 12.5 contravariant and covariant generic type arguments for delegates and interfaces

Category: C #

Covariance and contravariance of generics

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: 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.