2015-07-22 3 views
6

Angenommen, wir haben dieses Modell:Erweiterungsmethoden mit Schnittstelle

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

Ich habe eine Erweiterungsmethode für alle Klassen, die von AbstractTableReferentielEntity erben.

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

aber für eine bestimmte Art von AbstractTableReferentielEntity (wie EstimationTauxReussite), würde Ich mag eine bestimmte Aktion durchzuführen, so habe ich eine Methode zweite Verlängerung.

public static EntityItemViewModel ToEntityItem(this EstimationTauxReussite entity) {} 

Alle Erweiterungen Methoden im gleichen Namensraum deklariert werden.

Danach, rufe ich einige Daten aus einer DB mit Entity Framework:

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

Es kompiliert.

Wenn T zur Laufzeit ein EstimationTauxReussite-Typ ist, geht es in die falsche Methode ToEntityItem, wenn ich Select(item => item.ToEntityItem()) aufrufen. Es geht nicht auf die spezifischste Erweiterungsmethode ein. Irgendwelche Ideen ?

+0

Eine Erweiterungsmethode sollte niemals Vorrang haben, daher ist dies ein merkwürdiges Verhalten. – NibblyPig

+0

Haben Sie Änderungen an der Datenbank vorgenommen? Wenn ja, aktualisieren Sie das Entity Framework. Ich habe auch die gleiche Art von Problem, wenn ich Änderungen an der Datenbank mache. – Nivs

+0

@Nivs, es hat nichts mit Entity Framework oder der Datenbank zu tun, nur weil Erweiterungsmethoden nur statische Methoden sind und daher nicht am Polymorphismus teilnehmen. –

Antwort

1

Das ist, weil Erweiterung Methoden nur syntaktischer Zucker für statische Methoden sind. Die aufzurufende Methode wird zur Kompilierzeit basierend auf dem Kompilierungszeittyp des Arguments aufgelöst, es ist kein virtueller Versand beteiligt.

In Ihrer GetAllActifEntityItem Methode, der Compiler weiß nur, dass T ein AbstractTableReferentielEntity ist, so löst es die ToEntityItem Verfahren auf dieser Grundlage. Die Tatsache, dass es tatsächlich mit EstimationTauxReussite für T aufgerufen wird, ist irrelevant.

Eine mögliche Problemumgehung wäre ToEntityItem eine virtuelle Mitgliedsmethode von AbstractTableReferentielEntity, und überschreiben Sie es in EstimationTauxReussite. Auf diese Weise wird der virtuelle Versand wie erwartet ausgeführt und die richtige Methode wird aufgerufen.

+0

Wenn Sie wissen, dass es offensichtlich ist. Ihr Workaround hat für mich funktioniert, danke! :) –

1

Wenn ich Zugriff auf Quellen von AbstractTableReferentielEntity habe und EstimationTauxReussite Klassen ich würde ihnen ein Remake in Weggefolgschaft

  1. virtuelle ToEntityItem Methode In der AbstractTableReferentielEntity Klasse
  2. außer Kraft setzt es in EstimationTauxReussite Klasse
  3. löschen beide Erweiterungsmethoden

Jetzt Select(item => item.ToEntityItem()) sollte wählen Methode hängt von Eingabeobjekt

3

Der Grund ist, dass Erweiterungsmethoden "syntaktischer Zucker" sind, dh sie sind ein Compiler-Trick. Ihre Linie:

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

wird wirksam durch den Compiler konvertiert:

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

und dann verwandelte sich in IL. Dies bedeutet, dass der Typ item zur Kompilierzeit, nicht zur Laufzeit ermittelt werden muss. Daher wird die AbstractTableReferentielEntity Version der Erweiterungsmethode verwendet, da dies der Typ ist, der beim Kompilieren mit dem Typ übereinstimmt.