Resilience and Covariance of C Generic Interface

  • 2021-12-11 18:46:13
  • OfStack

1. Covariance of generic interfaces

If a generic type is annotated with the out keyword, the generic interface is covariant. This also means that the return type can only be T.

Resilience of generic interfaces

If a generic type is annotated with the in keyword, the generic interface is resilient. In this way, the interface can only use the generic type T as the input to its method, that is, the parameter of the method.

This is the definition of resilience and covariance of generic interfaces, so let's explain it with code, directly on the code.


/// <summary>
 ///  Generic interface 
 /// </summary>
 /// <typeparam name="T"></typeparam>
 public interface IDisplay< T >
 {
  void Show(T item);
 }
 /// <summary>
 ///  Implement a generic interface IDisaplay
 /// </summary>
 /// <typeparam name="T"></typeparam>
 public class ShapDisplay<T> : IDisplay<T>
 {
  public void Show(T item)
  {
   Console.WriteLine(" The test was successful! ");
  }
 }
 /// <summary>
 ///  Parent class 
 /// </summary>
 public class ParentClass
 {
 }
 /// <summary>
 ///  Subclass 
 /// </summary>
 public class SubClass : ParentClass
 {
 }

2. The interface is defined and implemented above. Next, we will test the class that implements the interface and the code on it


class Program
 {
  static void Main(string[] args)
  {
   //  Instantiating a generic class with a subclass ( Abbreviated subclass object )
   IDisplay<SubClass> sub1 = new ShapDisplay<SubClass>();

   //  Instantiating a generic class with a parent class ( Abbreviated as parent class object )
   IDisplay<ParentClass> par1 = new ShapDisplay<ParentClass>();

   //  Receive subclass objects with parent class types ( Subclass object → parent class type ) Covariance 
   IDisplay<ParentClass> parent = sub1;

   //  Receive parent class objects with subclass types ( Parent class object → subclass type ) Anti-change 
   IDisplay<SubClass> sub = par1;

   Console.ReadKey();
  }
 }

We will find that lines 12 and 15 will report errors, but why?

The reason is very simple, because when we define the interface like this at the top, we don't add out or in, that is, generic interfaces don't support resilience and covariance by default, so compilation will report errors.

OK, then let's modify the generic interface by 1, as follows


/// <summary>
 ///  Generic interface 
 /// </summary>
 /// <typeparam name="T"></typeparam>
 public interface IDisplay<out T>
 {
  void Show(T item);
 }

When you add out before a generic type, you will find that Show in the interface will report an error. Why?

Depending on the covariance of the generic interface, if the generic type is annotated with the out keyword, this means that the return type can only be T. That is to say, the return type of the method should be T, while in our Show method, the parameter of the method is T, so it does not meet the requirements and reports an error.

Then let's modify the code again, as follows


/// <summary>
 ///  Generic interface 
 /// </summary>
 /// <typeparam name="T"></typeparam>
 public interface IDisplay<in T>
 {
  void Show(T item);
 }

The interface is completely fine, but, sorry, 12 lines in the main method still report errors, wtf?

Because the generic type is annotated with in, this means that the generic only supports resilience, and 12 lines of code are covariant, so an error will be reported.

At this point, the resilience and covariance of generic interfaces are explained, and the following three points are summarized.

① Generic interface. If there is no keyword out or in before the generic type, the generic interface does not support resilience and covariance, that is, only what object points to what type.

② If the generic interface and generic type are marked with the keyword out, it means that the output of its method is T type, that is, the return value of the method. At the same time, the generic interface supports covariance, that is, the type of the parent class can be used to point to the objects of the subclass.

③ If the generic interface and generic type are marked with the keyword in, it means that the input of its method is T type, that is, the parameter of the method. This generic interface supports variability, that is, the type of a subclass can be used to point to the object of a parent class.


Related articles: