Preface
In C#, covariance and inverse are two important concepts, mainly used to deal with the variability of generic type parameters.
These two concepts allow for more flexible conversions between generic types, improving code reusability and flexibility.
Covariance
(I) Definition and Concept
Covariation allows converting a generic parameter of a derived type to a generic parameter of a base type.
Simply put, if there are two generic interfaces IFoo and IBar, and the generic parameter T of IFoo is covariant, then if A is a derived class of B, IFoo can be converted to IFoo。
(II) Usage scenarios and examples
Example 1: Covariance in generic interfaces
interface IFoo<out T> { T GetValue(); }
Suppose we have the following interface definition:
Hereout
Keyword representationT
It is covariant. Now we can use this interface like this:
class Animal {} class Dog : Animal {} class Program { static void Main() { IFoo<Dog> dogFoo = new DogFoo(); IFoo<Animal> animalFoo = dogFoo; // Covariance conversion allows Animal animal = (); } } class DogFoo : IFoo<Dog> { public Dog GetValue() { return new Dog(); } }
In this example, since IFoo's T is covariant, we can convert IFoo to IFoo.
This is because Dog is an derived class of Animal, and the GetValue method only returns a value of type T and will not modify it, so this conversion is safe.
Example 2: Covariance in delegation
delegate T Func<out T>(); class Program { static void Main() { Func<Dog> dogFunc = GetDog; Func<Animal> animalFunc = dogFunc; // Covariance conversion allows Animal animal = animalFunc(); } static Dog GetDog() { return new Dog(); } }
Delegations in C# can also support covariance.
For example:
The commission hereFunc<out T>
ofT
It is covariant, so it can beFunc<Dog>
Convert toFunc<Animal>
。
Inversion
(I) Definition and Concept
Inverting allows converting generic parameters of a base type to generic parameters of a derived type.
If there are two generic interfacesIFoo<T>
andIBar<T>
,andIFoo<T>
Generic parameters ofT
It is inverted, then ifA
yesB
The derived class can be used toIFoo<B>
Convert toIFoo<A>
。
(II) Usage scenarios and examples
Example 1: Inversion in generic interfaces
Consider the following interface definitions:
interface IBar<in T> { void SetValue(T value); }
The in keyword here means that T is inverted.
Now we can use this interface like this:
class Animal {} class Dog : Animal {} class Program { static void Main() { IBar<Animal> animalBar = new AnimalBar(); IBar<Dog> dogBar = animalBar; // Inverter conversion allows (new Dog()); } } class AnimalBar : IBar<Animal> { public void SetValue(Animal value) {} }
In this example, since the T of IBar is inverted, we can convert IBar to IBar.
This is because the SetValue method accepts a T-type parameter and Dog is an Animal derived class, so the Dog-type parameter can be passed to a method that accepts Animal-type parameters, and this conversion is safe.
Example 2: Inversion in delegation
delegate void Action<in T>(T value); class Program { static void Main() { Action<Animal> animalAction = SetAnimal; Action<Dog> dogAction = animalAction; // Inverter conversion allows dogAction(new Dog()); } static void SetAnimal(Animal value) {} }
Delegation can also support inverter.
For example:
The commission hereAction<in T>
ofT
It is inverted, so it can beAction<Animal>
Convert toAction<Dog>
。
Limitations and precautions for covariance and inversion
(I) Limitation of generic type parameters
For covariant generic type parameters, they can only appear as return value types in interfaces or delegates, and cannot be used as parameter types of methods.
For example, the following code is illegal:
interface IFoo<out T> { void DoSomething(T value); // Error, covariant type cannot be used as a parameter}
For inverter generic type parameters, they can only appear as parameter types of methods in interfaces or delegates, and cannot be used as return value types.
For example, the following code is illegal:
interface IBar<in T> { T GetValue(); // Error, the inverter type cannot be used as the return value}
(II) Covariance and inversion of arrays
Arrays in C# support covariance to a certain extent, but this covariance is not safe.
For example:
Animal[] animals = new Dog[10]; // Compilation passes, but an exception may be thrown during runtimeanimals[0] = new Cat(); // If this is a Cat Object,An exception will be thrown during runtime
Unlike arrays, covariance and inversion of generic types are safe because the compiler performs type checks at compile time to ensure the security of the conversion.
(III) The scope of variability
Covariance and inversion are only applicable to reference types and are not applicable to value types.
For example, the following code is illegal:
interface IFoo<out T> where T : struct // Error, covariance cannot be used for value types{ T GetValue(); }
Summarize
Covariance and inversion are powerful concepts in C# that can improve code flexibility and reusability.
By using covariance and inversion correctly, safe conversions between generic types can be performed, making the code more concise and easy to maintain.
However, when using covariance and inversion, attention should be paid to the limitations and security of type parameters to avoid potential runtime errors
The above is personal experience. I hope you can give you a reference and I hope you can support me more.