.net core 中的 Func delegate 是如何进行逆变工作的

How does contravariance work with Func delegate in .net core

我有以下代码,我试图为我的域对象编写通用验证规则。在这样做的同时我有一个问题来处理 Func delegate supporting variance

public class Person { }
public class Employee : Person { }

internal interface IValidation<T> where T: Person  
{
     void AddValidationRule(Func<T,bool> predicateFunction);
}

internal class BaseValidation : IValidation<Person>
{
    void IValidation<Person>.RegisterValidationRules(Person person)
    {

    }
}

internal class EmployeeValidation : BaseValidation
{
    void RegisterValidation()
    {
        Func<Employee,bool> empPredicate = CheckJoiningDate;
        base.AddValidationRule(empPredicate);
    }

    bool CheckJoiningDate(Employee employee)
    {
        return employee.JoiningDate > DateTime.Now.AddDays(-1) ;
    }
}

有了上面的代码,编译器会给出一条错误消息说

Compiler Error on line : base.AddValidationRule(empPredicate); Argument 1: cannot convert from 'System.Func<>Employee, bool>' to 'System.Func<>Person, bool>

我已经提到了这个 https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/dd465122%28v%3dvs.100%29 但我仍然无法让编译器理解这里的逆变,

感谢您的帮助,让我更好地理解这一点

cannot convert from 'System.Func<>Employee, bool>' to 'System.Func<>Person, bool>

base.AddValidationRule 需要一个可以对任何 Person 进行操作的函数。您的功能只能在 Exployee 上运行,这更具限制性。这是错误的方差形式。

此处未显示,但可能 BaseValidation 已实施 IValidation<Person>

可能,最好的解决方法是确保您从 IValidation<Employee> 继承,可能是通过使 BaseValidation 通用。

这行得通吗?

internal class BaseValidation<T> : IValidation<T>
{
    void IValidation<T>.RegisterValidationRules(T entity)
    {
    }
}

internal class EmployeeValidation : BaseValidation<Employee>
{
 //...
}

你混淆了协变和逆变。

通过协变,泛型类型参数可以 "smaller" 超出要求。也就是说,如果我们有:

Func<Mammal, Mammal> f1 = whatever;
Func<Mammal, Animal> f2 = f1;

为什么这样行得通? Func 在其第二个参数中是 协变 f2 期待 returns Animal 的代表。它得到了一个returns smaller 类型的代表; MammalAnimal 少,所以 Mammal 更小

想想为什么会这样。当有人呼叫 f2 时,他们希望找回动物。但如果他们真的调用 f1,他们仍然得到一个动物,因为每个哺乳动物都是动物。

通过协变,泛型类型的 "size" 与类型参数的大小 在同一方向 上变化。 Mammal 小于 AnimalFunc<Mammal, Mammal> 小于 Func<Mammal, Animal>。这就是为什么它是 "co" 方差,co meaning "together".

逆变是相反的,因此"contra",意思是"against"。使用逆变,泛型类型参数可以比预期的更大:

 Func<Giraffe, Mammal> f3 = f1;

f3 需要一个带长颈鹿的函数;我们有一个函数需要更大的类型,哺乳动物。它更大,因为哺乳动物比长颈鹿多。逆变说这很好,那应该是有道理的。如果有人用长颈鹿调用 f3,如果这实际上是对 f2 的调用也没关系,因为 f2 可以带长颈鹿;它可以带走任何哺乳动物。

你混淆了协变和逆变;您期望可以以协变方式使用逆变参数,这是错误的。接受雇员的函数不能转换为接受人员的函数,因为您可以将非雇员人员传递给它。接受员工的函数可以转换为接受经理的函数,因为所有经理都是员工。