Analysis of covariant and contravariant examples of C4.0

  • 2020-10-07 18:51:17
  • OfStack

This article illustrates the covariant and contravariant features of C#4.0, which will help you master C#4.0 program design step by step. The specific analysis is as follows:

1. Covariant and contravariant before C#3.0

If this is the first time you've heard these two words, don't worry, they're actually quite common. The covariant and contravariant (Covariance and contravariance) in C#4.0 is a step closer, with two run-time (implicit) generic type parameter conversions. In simple terms, a covariant (Covariance) is when a type is raised from "small" to "large", such as from a subclass to a parent; Contravariant is to point to change from "big" to "small", both have different conditions and USES. The following example illustrates C#3.0's previous support for covariant and contravariant:

Code 1


public class Animal { }
public class Cat : Animal { }

public delegate Animal AniHandler(Animal a);
public static Animal AniMethod(Animal a) { return null; }
public static Cat CatMethod(Object o) { return null; }

public static void TestCovariance()
{
  AniHandler handler1 = AniMethod;
  AniHandler handler2 = CatMethod;// It's legal here 
}

While CatMethod here does not strictly meet the delegate AniHandler's signature, it is legal for it to be used as AniHandler in covariant (Cat-) > Animal) and contravariant (object- > Animal), the delegate points to a method where the parameter passed in can be a large, broad type, and the result returned can be a smaller, more precise type (subclass), because it contains more information. When calling a method, the argument can be a "small" subclass, and the return value can be used as a "big" superclass. The following calls are valid:


object o = AniMethod(new Cat());

Well, that sounds a little confusing, but Now I'm going to try to make it clear and concise. Whether covariant or contravariant, it is intended to make a very reasonable fact true: if more type information is provided than is needed (rather than equal to it), then this is certainly possible. In the example in code 1, the AniHandler delegate requires 1 Animal as the return value, but I give it back 1 Cat. Cat contains all the features of Animal, which is certainly possible. This is covariant; At the same time, AniHandler needs 1 Animal as a parameter, so in order for the function to get more information than it needs, I can just ask for 1 object to be passed in, which is certainly possible, and that's the contravariant.

2. Covariant in C#4.0

Let's first look at how harmonious covariance occurs in 1. The covariant in C#4.0 is very similar to the loose delegate in C#3.0, and the new C# covariant feature is also present in the generic interface or in the type parameters of the generic delegate. Taking the classic Animal and Cat example again, after looking at code 1 above, since Cat CatMethod() can be used as Animal AniHandler, you have every reason to believe that the following code is also valid in C#3.0:

Code 3


delegate T THandler<T>();

static void Main(string[] args)
{      
  THandler<Cat> catHandler= () => new Cat();
  THandler<Animal> aniHandler = catHandler;//Covariance 
}

Unfortunately, you are wrong. In C#3.0, the above code will not compile and you will be told that an error has occurred!

Times have improved and the above is now supported by the compiler in C#4.0. You only need to add one out keyword before declaring the type parameter of THandler:


delegate T THandler<out T>();

Using a single keyword instead of allowing implicit conversions directly is also a type-safety concern. So when you write Covariance, you should know what Covariance is likely to happen.

3. Contravariant in C#4

We continue to use the Animal and Cat examples. In VS2008, the following code does not compile:

Code 5


delegate void THandler<T>(T t);  
public static void TestContravariance()
{
  THandler<Animal> aniHandler = (ani) => { };
  THandler<Cat> catHandler = aniHandler;
}

In VS2010, well, no. If you put the keyword "in" in front of the type parameter T, that is, delegate void THandler < in T > (T t); Cat- can be implemented > Animal Contravariance.

4. Conclusion:

The covariant and contravariant features in C#4 make generic programming type-casting more natural, but note that the covariant and contravariant features mentioned above only work between reference types and are currently used only for generic interfaces and delegates. An T parameter can only be in or out. You cannot do this if you want to invert your delegate parameter and return covariant values (as shown in code 1).

I believe that what I have described in this paper can be used as a reference for you to better grasp the C#4.0 program design.


Related articles: