Covariance and Contravariance
Example: Manager is a subclass of Employee, but List<Manager> is not a subclass of List<Employee>. This makes sense since List<Manager> does not inherit anything from List<Employee>.
But for a delegate, which takes inputs and return an output, if the
delegate A takes an instance of Manager as input and return an instance of Employee as output
delegate B takes an instance of Employee as input and return an instance of Manager as output
then a value of delegate A can be assigned to delegate B in theory.
we can do Employee e = A(new Manager()); and Manager m = B(new Employee());. But for delegate B, we also can do Employee e = B(new Manager()); because
we can assign Manager to Employee. So we can assign A to B in theory. And the theory is implemented in C# by the feature of covariance and contravariance.
** The feature is only applied to generic delegate and interface. **
-
Contravariance (reserve the potential of input, 浪费了这个function在 in 上的能力)
If a superclass can be an input, then its subclasses can also be the input.
public class Parent{
public string name;
}
public class Child: Parent{
public string value;
}
// Action <in T>(T obj);
Action<Parent> fun_print = (Parent obj) =>{
Console.WriteLine(obj.name);
};
// input of fun_print_child is a Child but we actually only used Parent's member.
Action<Child> fun_print_child = fun_print;
-
Covariance (reserve the potential of output, 浪费了这个function在 output 上的能力)
If a superclass can be an output, then its subclasses can also be the output.
Converter<string, Child> fun_convert_to_child = (string obj) =>{
return new Child{
name = obj,
value = obj
};
};
public delegate TOutput Converter<in TInput,out TOutput>(TInput input);
Converter<string, Parent> fun_convert_to_parent = fun_convert_to_child;
Parent p = fun_convert_to_parent("nothing");
Console.WriteLine(p.name);
-
Interface
Same principle applied to interface
public interface GenericInterface<in TInput, out TResult>
{
TResult GetResult();
void SetInput(TInput);
}
public class Program{
public static void Main(String [] args){
GenericInterface<SuperClass, SubClass> temp = new Parent<SuperClass, SubClass>();
GenericInterface<SubClass, SuperClass> temp2 = temp;
}
}