Interface Extension Methods

Suppose we have this model:

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

I created an extension method for all classes that inherit from AbstractTableReferentielEntity.

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

But for one specific type of AbstractTableReferentielEntity (e.g. EstimationTauxReussite) I would like to perform a specific action, so I created a second extension method.

  public static EntityItemViewModel ToEntityItem(this EstimationTauxReussite entity) {} 

All extension methods are declared in the same namespace.

After that, I retrieve some data from the database using the Entity Framework:

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

It compiles.

When T is an EstimationTauxReussite type at runtime, it goes into the wrong ToEntityItem method when I call Select(item => item.ToEntityItem()) . It is not included in the most specific extension method. Any ideas?

+6
source share
3 answers

This is because extension methods are just syntactic sugar for static methods. The call method is allowed at compile time based on the type of compilation time, there is no virtual send.

In your GetAllActifEntityItem method GetAllActifEntityItem compiler only knows that T is AbstractTableReferentielEntity , so it solves the ToEntityItem method based on this. The fact that it will actually be called using EstimationTauxReussite for T does not matter.

A possible workaround would be to make the ToEntityItem virtual participant's AbstractTableReferentielEntity method and override it in EstimationTauxReussite . Thus, the virtual dispatch will be performed as expected, and the correct method will be called.

+1
source

The reason is that extension methods are "syntactic sugar", i.e. they are a compiler. Your line:

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

effectively converted by the compiler to:

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

and then turned into IL. This means that the type item must be determined at compile time, and not at run time. Thus, the version of the AbstractTableReferentielEntity extension method is used as the one that matches the type at compile time.

+3
source

If I have access to the sources of AbstractTableReferentielEntity and EstimationTauxReussite classes , I would redo them as follows

  • Add virtual ToEntityItem method to AbstractTableReferentielEntity class
  • Cancel it in the EstimationTauxReussite class
  • Delete both extension methods

Now Select(item => item.ToEntityItem()) should select a method depending on the input object

+1
source

All Articles