About covariant and Inverter
Covariance and inversion are collectively referred to as variants. This is the syntax rule for implicit reference conversion between arrays, Delegate types, and generic parameter types, which is somewhat similar to polymorphism.
Variants in generic Interfaces
<1> covariant
The generic return type of the method declared in the interface. It can accept a larger return type.
interface ICovariant
{ R GetSomething(); // The following statement generates a compiler error. // void SetSometing(R sampleArg);}
<2> Inverter
The generic parameter type of the method declared in the interface. It can accept a parameter type with a smaller degree of derivation.
interface IContravariant
{ void SetSomething(A sampleArg); void DoSomething
() where T : A; // The following statement generates a compiler error. // A GetSomething(); }
<3> simultaneous implementation of coordination and resistance to changes
interface IVariant
{ R GetSomething(); void SetSomething(A sampleArg); R GetSetSometings(A sampleArg);}
<4> understanding about variants
Variants include variable resistance and covariant. They are used to handle the assignment of classes in the generic type and the classes in the delegate and the derived classes, so they are similar to polymorphism.
It is easy to understand about covariant. It grants a lower level of derivation to the lower level. In a generic interface, the identifier of the covariant is out, and it represents the return of the function.
Return value, which indicates that it is similar.
For the variable resistance, the interface indicates in, and it indicates the input function parameters. Therefore, the representation of the variable resistance is that the lower-level derivation is assigned to the higher-level derivation.
Input with a high degree of derivation to function parameters with a low degree of derivation.
Example of anti-change:
namespace ConsoleApplication24{ // Simple hierarchy of classes. public class Person { public string FirstName { get; set; } public string LastName { get; set; } } public class Employee : Person { } // The custom comparer for the Person type // with standard implementations of Equals() // and GetHashCode() methods. class PersonComparer : IEqualityComparer
{ public bool Equals(Person x, Person y) { if (Object.ReferenceEquals(x, y)) return true; if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false; return x.FirstName == y.FirstName && x.LastName == y.LastName; } public int GetHashCode(Person person) { if (Object.ReferenceEquals(person, null)) return 0; int hashFirstName = person.FirstName == null ? 0 : person.FirstName.GetHashCode(); int hashLastName = person.LastName.GetHashCode(); return hashFirstName ^ hashLastName; } } class Program { public static void Test() { List
employees = new List
{ new Employee() {FirstName = "Michael", LastName = "Alexander"}, new Employee() {FirstName = "Jeff", LastName = "Price"} }; // You can pass PersonComparer, // which implements IEqualityComparer
, // although the method expects IEqualityComparer
. IEnumerable
noduplicates = employees.Distinct
(new PersonComparer()); foreach (var employee in noduplicates) Console.WriteLine(employee.FirstName + " " + employee.LastName); } public static void Main() { Test(); } }}
Variations in generic parameters
<1>
To enable implicit conversion, you must use the in or out keyword.
Public delegate T SampleGenericDelegate
(); Public static void Test () {SampleGenericDelegate
DString = () => ""; // You can assign delegates to each other, // because the type T is declared covariant. SampleGenericDelegate
DObject = dString ;}
<2>
If you only use the variant support to match the method signature and delegate type, and do not use the in and out keywords, you may find that, sometimes multiple delegates can be instantiated using the same lambda expression or method, but one delegate cannot be assigned to another delegate.
public static void Test(){ SampleGenericDelegate
dString = () => " "; SampleGenericDelegate
dObject = () => " "; // SampleGenericDelegate dObject = dString;//error}