带接口的扩展方法
本文关键字:方法 扩展 接口 | 更新日期: 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
方法中,编译器只知道T
是AbstractTableReferentielEntity
,所以它在此基础上解析ToEntityItem
方法。对于T
,它实际上会被EstimationTauxReussite
调用,这是无关紧要的。
一个可能的解决方法是使ToEntityItem
成为AbstractTableReferentielEntity
的虚成员方法,并在EstimationTauxReussite
中重写它。这样,虚拟分派将按预期发生,并将调用正确的方法。
如果我可以访问AbstractTableReferentielEntity
和EstimationTauxReussite
类的源代码我将按照以下方式重新制作它们
- 添加虚拟ToEntityItem方法到AbstractTableReferentielEntity类
- 在EstimationTauxReussite类中重写
- 删除两个扩展方法
现在Select(item => item.ToEntityItem())
应该选择方法取决于输入对象