假设我们有这个模型:
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) {}
所有扩展方法都在同一名称空间中声明。
之后,我从具有Entity Framework的数据库中检索一些数据:
protected List<EntityItemViewModel> GetAllActifEntityItem<T>()
where T : AbstractTableReferentielEntity
{
return Context
.Set<T>()
.Where(item => item.IsActif)
.Select(item => item.ToEntityItem())
.ToList();
}
它编译。</ p>
当运行时的T是EstimationTauxReussite类型时,当我调用ToEntityItem
时,它会进入错误的方法Select(item => item.ToEntityItem())
。它没有进入最具体的扩展方法。有任何想法吗 ?
答案 0 :(得分:3)
原因是扩展方法是&#34;语法糖&#34;,即它们是编译技巧。你的行:
.Select(item => item.ToEntityItem())
被编译器有效地转换为:
.Select(item => StaticClassWithExtensionMethod.ToEntityItem(item))
然后变成了IL。这意味着item
的类型必须在编译时确定,而不是在运行时确定。所以扩展方法的AbstractTableReferentielEntity
版本被用作编译时匹配类型的那个。
答案 1 :(得分:1)
如果我可以访问AbstractTableReferentielEntity
和EstimationTauxReussite
类的来源,我会按以下方式重新制作它们
现在Select(item => item.ToEntityItem())
应该选择方法取决于输入对象
答案 2 :(得分:1)
那是因为扩展方法只是静态方法的语法糖。调用方法在编译时根据参数的编译时类型解析,不涉及虚拟调度。
在GetAllActifEntityItem
方法中,编译器只知道T
是AbstractTableReferentielEntity
,因此它会基于此解析ToEntityItem
方法。 <{1}} EstimationTauxReussite
实际调用它的事实无关紧要。
可能的解决方法是使T
成为ToEntityItem
的虚拟成员方法,并在AbstractTableReferentielEntity
中覆盖它。这样,虚拟调度将按预期发生,并将调用正确的方法。