2010-03-03 11 views
6

Übergabe eines Ausdrucks an eine Linq-Abfrage verhält sich je nach Syntax unterschiedlich, und ich frage mich, warum dies der Fall ist.Linq wo Schlüsselwort vs. Where Erweiterung und Ausdruck Parameter

Lassen Sie uns sagen, ich habe diese sehr allgemeine Funktion

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 

Die folgende Implementierung als

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return (from c in _ctx.Companies.Where(whereClause) select c); 
} 

Aber das nächste Implementierung dauert nicht nicht kompilieren (Delegate ‚System.Func‘ erwartet funktioniert 1 Argumente)

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return (from c in _ctx.Companies where whereClause select c); 
} 

Offensichtlich Ich kann nur die erste Syntax verwenden, aber ich habe mich nur gewundert, warum der Compiler das where-Schlüsselwort nicht wie die Where-Erweiterung behandelt?

Danke, Thomas

Antwort

3

Die Syntax für eine Abfrage Ausdruck einer where Klausel beteiligt ist (vereinfacht die vollständige Grammatik)

from identifier in expression where boolean-expression select expression 

whereClause ist kein boolescher Ausdruck. Um recitify Dazu muss man sagen,

from c in _ctx.Companies where whereClause.Compile()(c) select c; 

Beachten Sie, dass, wenn whereClause waren ein Func<Company, bool> Sie konnten entkommen mit

from c in _ctx.Companies where whereClause(c) select c; 

Beachten Sie, dass

from x in e where f 

wird mechanisch durch den Compiler in übersetzt

(from x in e).Where(x => f) 

Ich sage mechanisch, weil es diese Übersetzung durchführt, ohne eine semantische Analyse zu machen, um die Gültigkeit der Methodenaufrufe etc. zu überprüfen. Diese Phase kommt später, nachdem alle Abfrageausdrücke in LINQ-Methodenaufrufausdrücke übersetzt wurden.

Insbesondere

from c in _ctx.Companies where whereClause select c 

ist

_ctx.Companies.Where(c => whereClause).Select(c) 

übersetzt, die eindeutig unsinnig ist.

Der Grund, dass

from c in _ctx.Companies.Where(whereClause) select c 

legit ist, weil eine Überladung IEnumerable<Company>.Where hat eine Func<Company, bool> akzeptieren, und es gibt eine implizite Umwandlung von einem Expression<Func<Company, bool>> zu einer Func<Company, bool>.

+0

Wenn Sie Func als Argument anstelle von Expression > akzeptieren würden, hätten Sie Prädikat als Parametertyp verwenden können. –

+0

Ja, das ist ein vereinfachtes Beispiel, nur um sich auf die Unterschiede zu konzentrieren. Der Grund für die Verwendung eines Ausdrucks > ist, dass ich möchte, dass der Speicherort in der Datenbank und nicht im Speicher ausgeführt wird. –

0

Der Unterschied ist, dass in SQL-ähnlichen, wo es Ausdruck erwartet, dass in bool auswertet. Aber in Where-Methode kann der Typ des Ausdrucks der Delegat sein.

zu zweiten zwingen Sie arbeiten können Parameter whereClause.Compile()(c) oder ändern ändern Func<Company, bool> whereClause und whereClause(c)

2

Sie können die ganze Sache tatsächlich verkürzen:

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return _ctx.Companies.Where(whereClause); 
} 

Wenn Sie die LINQ-Syntax verwenden, wird der Code in der where Klausel einer Expression<> übersetzt in, die einen Codebaum darstellt. Wenn Sie Expression<Func<Customer, bool>> akzeptieren, sagen Sie, dass Ihre Methode eine Codebaumstruktur akzeptiert, die vom Compiler aus C# -Code konvertiert wird.

Da Sie bereits den Codebaum haben, müssen Sie ihn direkt an die Where()-Methode übergeben, anstatt die LINQ-Syntax zu verwenden.

+0

Ja, ich weiß, dass mein Beispiel gemacht wurde, um zu verdeutlichen, wo der Unterschied auftritt, d. H. Wo und wo. Danke aber :). –