逆变如何在 .net core 中与 Func 委托一起工作



我有以下一段代码,我正在尝试为我的域对象编写通用验证规则。 这样做时,我有一个问题要处理 Func 委托支持方差

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) ;
}
}

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

编译器错误在线:基本。AddValidationRule(empPredicate); 参数 1:无法从 'System.Func<>Employee, bool>' 转换为 'System.Func<>Person,bool>

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

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

你混淆了协方差和逆变。

使用协方差时,泛型类型参数可以"小于"所需参数。 也就是说,如果我们有:

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

为什么会这样?Func在其第二个参数中是协变的。f2期待返回Animal的委托。它有一个返回较小类型的委托;Mammals比Animals 少,因此Mammal更小

想想为什么会这样。当有人打电话给f2时,他们希望能把动物找回来。 但如果他们真的叫f1,他们仍然会得到一种动物,因为每只哺乳动物都是动物。

使用协方差时,泛型类型的"大小"与类型参数的大小方向相同Mammal小于Animal.Func<Mammal, Mammal>小于Func<Mammal, Animal>。 这就是为什么它是"共同"方差,co的意思是"在一起"。

逆变是相反的,因此"反对",意思是"反对"。 对于逆变,泛型类型参数可能大于预期:

Func<Giraffe, Mammal> f3 = f1;

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

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

无法从"System.Func<>Employee, bool>"转换为"System.Func<>Person, bool>

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

此处未显示,但可能BaseValidationIValidation<Person>实现。

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

这行得通吗?

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

最新更新