2011-01-07 4 views
14

Considerando il codice seguente:Se si esegue il cast di un IQueryable come IEnumerable, si chiama un metodo di estensione Linq, che viene chiamata l'implementazione?

IQueryable<T> queryable; 

// something to instantiate queryable 

var enumerable = (IEnumerable<T>) queryable; 

var filtered = enumerable.Where(i => i > 3); 

Nella riga finale, il quale metodo di estensione viene chiamato?

È IEnumerable<T>.Where(...)? O sarà chiamato IQueryable<T>.Where(...) perché l'effettiva implementazione è ancora ovviamente interrogabile?

Presumibilmente, l'ideale sarebbe che venga chiamata la versione IQueryable, nello stesso modo in cui il normale polimorfismo utilizzerà sempre l'override più specifico.

In Visual Studio, tuttavia, quando faccio clic con il pulsante destro del mouse sul metodo Where e su "Vai alla definizione", sono portato alla versione IEnumerable, che ha senso da un punto di vista visivo.

La mia preoccupazione principale è che se da qualche parte nella mia app uso Linq su NHibernate per ottenere un interrogativo, ma lo passo usando un'interfaccia che usa la più generale firma IEnumerable, perderò le meraviglie dell'esecuzione del database posticipato !


Edit: Si scopre che, come Iridium ha fatto notare, è la versione Enumerable che viene chiamato

public class Program 
    { 
     static void Main(string[] args) 
     { 
      var myString2 = new MyString2(); 
      var myString = (MyString)myString2; 
      Console.WriteLine(myString.Method()); 
      Console.ReadLine(); 
     } 
    } 

    public class MyString {} 

    public class MyString2 : MyString {} 

    public static class ExtensionMethods 
    { 
     public static string Method(this MyString instance) 
     { 
      return "MyString method"; 
     } 

     public static string Method(this MyString2 instance) 
     { 
      return "MyString2 method"; 
     } 
    } 

L'uscita è "il metodo MyString".

+0

Hai dimenticato di votare la domanda ... è stato interessante scoprirlo :). –

+0

http://stackoverflow.com/questions/474074/overriding-extension-methods –

+3

Ricordate, la sintassi del metodo di estensione è solo uno zucchero sintattico per * chiamare un metodo statico * e metodi statici per definizione * utilizzare l'analisi statica per determinare quale metodo chiamata*. Se si desidera l'analisi * runtime *, è necessario scrivere il codice per farlo. Inoltre: non è * considerato * auspicabile per un IQ che sia staticamente un IE che si ritrasforma inaspettatamente al percorso del codice IQ; presumibilmente lo lanci su un IE perché tu * non * vuoi trattarlo come un QI! Se vuoi trattarlo come un QI, allora * non gettarlo via *. La regola di Groucho: se fa male quando lo fai, * non farlo *. –

risposta

8

La risposta attualmente accettata riguarda i metodi virtuali, non i metodi di estensione.

Se si esegue il cast di un IQueryable a un oggetto IEnumerable e quindi si chiama uno dei metodi di estensione (ad esempio Where (...) nella domanda), verrà chiamato quello su Enumerable, non Queryable.

3

Quando si esegue questo semplice programma, spiega come funziona l'overload :). La risposta è che verrà chiamato il metodo del tipo sottostante. E dovrebbe funzionare allo stesso modo per IQueryable e IEnumerable; vale a dire, il metodo dell'oggetto originale verrà chiamato poiché anche se lo abbiamo lanciato, l'implementazione effettiva è del tipo originale. Ma quando c'è un metodo di estensione viene usato il metodo di estensione per l'oggetto a cui si fa riferimento, quindi in quel caso dipende dalla logica nel metodo di estensione. Il metodo di estensione avrebbe potuto essere intelligente logit per vedere se l'oggetto è di un tipo effettivo e quindi eseguire il cast back prima di eseguire il metodo.

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyString2 myString2 = new MyString2(); 
     var myString = (MyString)myString2; 
     Console.WriteLine(myString); // prints "ToString of MyString2" 
     Console.WriteLine(myString.GiveMeTheString()); // prints "GiveMeTheString of MyString2" 
     Console.ReadLine(); 
    } 
} 

public class MyString 
{ 
    public string MyProperty { get; set; } 
    public override string ToString() 
    { 
     return "ToString of MyString"; 
    } 
} 
public class MyString2 : MyString 
{ 
    public string MyProperty { get; set; } 
    public override string ToString() 
    { 
     return "ToString of MyString2"; 
    } 
} 

public static class Extensions 
{ 
    public static string GiveMeTheString(this MyString myString) 
    { 
     return "GiveMeTheString of MyString"; 
    } 
    public static string GiveMeTheString(this MyString2 myString) 
    { 
     return "GiveMeTheString of MyString2"; 
    } 
} 
+0

Grazie, Tomas! Sapevo che avrei dovuto essere in grado di risolvere il problema codificando, ma il mio cervello non funzionava! Almeno ora, anche se qualcun altro alla ricerca della soluzione si spera troverà questo post. –

+0

Dovrei aggiungere: la risposta è che verrà chiamato il metodo di estensione più specifico (IQueryable). –

+0

Succede al meglio di noi. Ricorda di votare e di accettare la risposta in modo che altre persone possano trovare la risposta più facilmente; cioè, se è corretto. E aggiungerò quella parte da qualche parte nella mia risposta. –

Problemi correlati