2015-06-18 5 views
13

Nehmen wir an, ich brauche eine Erweiterungsmethode, die nur die benötigten Eigenschaften aus verschiedenen Quellen auswählt. Die Quelle könnte die Datenbank oder die Sammlung im Speicher sein. So habe ich eine solche Verlängerung definierte Methode:In welchen Fällen muss ich zwei verschiedene Erweiterungsmethoden für IEnumerable und IQueryable erstellen?

public IQueryable<TResult> SelectDynamic<TResult>(
      this IQueryable<T> source, 
      ...) 

Dies funktioniert gut für IQueryable s. Aber ich muss diese Funktion auch für IEnumerable s aufrufen.

Und in diesem Fall kann ich es nennen, mit Hilfe von .AsQueryable():

myEnumerable.AsQueryable() 
     .SelectDynamic(...) 
     .ToList(); 

Beide arbeiten gut. Und ich habe solche Frage, wenn beide gut funktionieren, in welchen Bedingungen Ich muss zwei verschiedene Erweiterungsmethoden für den gleichen Zweck erstellen, whike arbeitet man mit IEnumerable und die andere mit IQueryable?

Meine Methode muss im Fall von Queryable Abfrage an die Datenbank senden.

Zum Beispiel, hier ist die Quelle der .Select Erweiterungsmethode innerhalb System.Linq Namespace:

ich meine Hauptfrage wieder bin zu wiederholen:

Meine Methode muss eine Abfrage an den Da senden Tabase im Fall von Queryable, aber nicht bei der Arbeit mit IEnumerable. Und jetzt verwende ich AsQueryable() für die Aufzählungen. Weil ich nicht denselben Code für die Enumerable schreiben möchte. Kann es einige Nebenwirkungen haben?

+1

Eigentlich denke ich, das ist eine gute Frage, denn niemand scheint zu wissen, was AsQueryable wirklich macht. – usr

Antwort

2

myEnumerable.AsQueryable() gibt ein individuelles Objekt: new EnumerableQuery<TElement>(myEnumerable); (source code)

Diese EnumerableQuery Klasse implementiert IEnumerable<T> und IQueryable<T>

Wenn das EnumerableQuery Ergebnis .AsQueryable() als IEnumerable verwenden, die Implementierung der Schnittstellenmethode IEnumerable<T>.GetIterator() einfach den kehren Original Source Iterator, also keine Änderung und minimalen Overhead.später als IEnumerable ausgewertet werden, wenn der gesamte Ausdruck Baum verbraucht wird

Wenn die Implementierung der Schnittstelle Eigenschaft unter Verwendung des Ergebnisses von .AsQueryable() als IQueriable, kehrt IQueriable.Expression einfach Expression.Constant(this), bereit.

(Alle anderen Methoden und Codepfade von EnumerableQuery sind nicht wirklich relevant, wenn die EnumerableQuery direkt aus einem IEnumerable aufgebaut ist, soweit ich das beurteilen kann)

Wenn ich Sie richtig verstehe, haben Sie Ihre umgesetzt Methode selectDynamic<TResult>() in der Weise, dass Sie innerhalb der Methode einen Ausdrucksbaum konstruieren, der beim Kompilieren das gewünschte Ergebnis liefert.

Soweit ich den Quellcode verstehe, wenn Sie z. myEnumerable.AsEnumerable().selectDynamic().ToList(), der von Ihnen erstellte Ausdrucksbaum ist auf myEnumerable kompiliert und ausgeführt, und der Gesamtaufwand sollte ziemlich minimal sein, da all diese Arbeit nur einmal pro Abfrage ausgeführt wird, nicht einmal pro Element.

Also ich denke, es ist nichts falsch mit Ihrer IEnumerable Erweiterung Methode, wie diese Umsetzung:

public IEnumerable<TResult> SelectDynamic<TResult>(
     this IEnumerable<T> source,...) 
    return source.AsQueryable().SelectDynamic(); 
} 

Es gibt einig leichten Kopf ist, da dies die Abfrage kompiliert einmal jedes Mal diese Methode aufgerufen wird, und ich bin nicht Sicher, der JITer ist schlau genug, um diese Zusammenstellung zwischenzuspeichern. Aber ich denke, das wird in den meisten Fällen nicht auffallen, es sei denn, Sie führen diese Abfrage tausendmal pro Sekunde aus.

Abgesehen von leichten Leistungsproblemen sollten keine anderen Seiteneffekte bei der Implementierung der IEnumerable-Erweiterungsmethode auf diese Weise auftreten.

+0

Danke für die Antwort. Ich markiere das als eine Antwort. Dieser Satz hat mich dazu gebracht, den Prozess besser zu verstehen: ** Es gibt einen kleinen Overhead, da dies die Abfrage jedes Mal kompiliert, wenn diese Methode aufgerufen wird, und ich bin nicht sicher, ob der JITer intelligent genug ist, diese Kompilierung zwischenzuspeichern. ** –

5

Wenn Ihr Code nur tatsächlich funktioniert, wenn die Objekte mit seinem Beschäftigen in den Speicher geladen, sondern nur die IEnumerable Variante liefern und lassen Sie Ihre Anrufer entscheiden, wenn sie eine IQueryable in eine In-Memory-IEnumerable konvertieren möchten.

Im Allgemeinen werden Sie keine neuen Variationen um IQueryable implementieren, es sei denn, Sie schreiben einen neuen Datenbankanbieter.

+0

Ich hatte eine halb (schlecht) geschriebene Antwort in derselben Richtung - wenn Sie 'IQueryable'-Erweiterungen schreiben, müssen Sie versuchen, sicherzustellen, dass Sie es als' IQueryable' behandeln und die Abfrage in Wirklichkeit nicht lösen Ihr Code –

+1

Meine Methode muss eine Abfrage an die Datenbank senden, wenn 'Queryable', aber nicht bei der Arbeit mit' IEnumerable'. Und für den Moment benutze ich 'AsQueryable' für die Zahl. Weil ich nicht denselben Code für die Enumerables schreiben möchte. Kann es Nebenwirkungen haben? –

Verwandte Themen