带接口的扩展方法

本文关键字:方法 扩展 接口 | 更新日期: 2023-09-27 18:03:54

假设我们有这样的模型:

public abstract class AbstractTableReferentielEntity {}
public class EstimationTauxReussite : AbstractTableReferentielEntity { }

我为所有继承自AbstractTableReferentielEntity的类创建了一个扩展方法。

public static EntityItemViewModel ToEntityItem<T>(this T entity)
    where T : AbstractTableReferentielEntity {}

但是对于一个特定类型的AbstractTableReferentielEntity(如EstimationTauxReussite),我想执行一个特定的操作,所以我创建了第二个扩展方法。

 public static EntityItemViewModel ToEntityItem(this EstimationTauxReussite entity) {}

所有的扩展方法都声明在同一个命名空间中

之后,我从实体框架数据库检索一些数据:

protected List<EntityItemViewModel> GetAllActifEntityItem<T>()
    where T : AbstractTableReferentielEntity
{
    return Context
        .Set<T>()
        .Where(item => item.IsActif)
        .Select(item => item.ToEntityItem())
        .ToList();
}

它编译。

当T在运行时是EstimationTauxReussite类型时,当我调用Select(item => item.ToEntityItem())时,它进入错误的方法ToEntityItem。它不涉及最具体的扩展方法。有什么想法吗?

带接口的扩展方法

原因是扩展方法是"语法糖",即它们是编译器的伎俩。你的线:

.Select(item => item.ToEntityItem())

被编译器有效地转换为:

.Select(item => StaticClassWithExtensionMethod.ToEntityItem(item))
这意味着item的类型必须在编译时确定,而不是在运行时确定。因此,使用AbstractTableReferentielEntity版本的扩展方法,因为它是在编译时匹配类型的方法。

这是因为扩展方法只是静态方法的语法糖。要调用的方法在编译时根据实参的编译时类型进行解析,不涉及虚拟分派。

在你的GetAllActifEntityItem方法中,编译器只知道TAbstractTableReferentielEntity,所以它在此基础上解析ToEntityItem方法。对于T,它实际上会被EstimationTauxReussite调用,这是无关紧要的。

一个可能的解决方法是使ToEntityItem成为AbstractTableReferentielEntity的虚成员方法,并在EstimationTauxReussite中重写它。这样,虚拟分派将按预期发生,并将调用正确的方法。

如果我可以访问AbstractTableReferentielEntityEstimationTauxReussite类的源代码我将按照以下方式重新制作它们

  1. 添加虚拟ToEntityItem方法到AbstractTableReferentielEntity类
  2. 在EstimationTauxReussite类中重写
  3. 删除两个扩展方法

现在Select(item => item.ToEntityItem())应该选择方法取决于输入对象