2010-03-07 7 views
8

Ho cercato di saperne di più sull'utilizzo degli alberi di espressione Lamba e quindi ho creato un semplice esempio. Ecco il codice, funziona in LINQPad se incollato come programma C#.Utilizzo di alberi Lambda Expressions con IEnumerable

void Main() 
{ 
    IEnumerable<User> list = GetUsers().Where(NameContains("a")); 
    list.Dump("Users"); 
} 

// Methods 
public IEnumerable<User> GetUsers() 
{ 
    yield return new User{Name = "andrew"}; 
    yield return new User{Name = "rob"}; 
    yield return new User{Name = "chris"}; 
    yield return new User{Name = "ryan"}; 
} 

public Expression<Func<User, bool>> NameContains(string namePart) 
{ 
    return u => u.Name.Contains(namePart); 
} 

// Classes 
public class User 
{ 
    public string Name { get; set; } 
} 

Ne risulta il seguente errore:

Gli argomenti di tipo per il metodo 'System.Linq.Enumerable.Where (System.Collections.Generic.IEnumerable, System.Func)' non può essere dedotto dall'uso. Prova a specificare esplicitamente gli argomenti del tipo.

Tuttavia, se mi basta sostituire la prima riga principale con questo:

IEnumerable<User> list = GetUsers().Where(u => u.Name.Contains("a")); 

Funziona benissimo. Puoi dirmi cosa sto sbagliando, per favore?

risposta

5

Il metodo Enumerable.Where prende uno Func<T, bool>, non uno Expression<Func<T, bool>>. Forse stai confondendo con Queryable.Where, che prende un'espressione come parametro ... Nel tuo caso non hai bisogno di un'espressione, hai solo bisogno di un delegato che possa essere eseguito su ogni elemento nella sequenza. Lo scopo delle espressioni è (principalmente) di essere analizzato e tradotto in qualcos'altro (SQL per esempio), per eseguire la query su un'origine dati esterna

+0

Sì, è esattamente quello che ho fatto di sbagliato. Penso di aver ancora bisogno di fare più letture su questo argomento per cercare di capirlo meglio. L'altro mio esempio stava usando IQueryable e questo funzionava bene, quando ho creato un nuovo esempio usando un elenco IEnumerable non funzionava. Non sono sicuro di cosa significhi significare la parola chiave Expression. – Loathian

+0

Il fatto che le espressioni lambda sono considerate come un delegato o un albero di espressioni dipende dal contesto. Nel codice, si dichiara il tipo restituito come espressione, e ciò indica al compilatore di considerare l'espressione lambda come un albero di espressioni, piuttosto che un delegato eseguibile. A proposito, espressione non è una parola chiave, è un tipo –

+0

D'oh ... digitare non parola chiave. Grazie Thomas. – Loathian

1

Modificare il tipo di ritorno di NameContains da Expression<Func<User, Bool>> in Func<User, Bool> semplicemente. In questa situazione, non è necessario restituire l'espressione, in realtà si desidera restituire il delegato compilato. C'è una differenza tra l'espressione che compone il lambda e il lambda (che è un delegato) stesso.

Se si invia un lambda in un metodo, il metodo può accettare il lambda sia come espressione, sia come tipo di delegato compilato, a seconda di cosa si specifica nei parametri. Se il tipo di parametro in entrata è un'espressione, è possibile inviare qualcosa che assomiglia a un delegato, tuttavia, se il metodo è in attesa di un delegato, è necessario assegnargli un delegato compilato, non semplicemente un'espressione. Detto questo, si può anche fare qualcosa di simile:

var certainUsers = GetUsers().Where(NameContains("a").Compile()); 

Il che compilare l'espressione, e restituire un Func<User, Bool>.

0

Le espressioni lambda possono essere trattate come codici (delegati) o come dati (alberi di espressione)

Nel tuo esempio stai tentando di trattare l'espressione lambda come codice.

Si utilizzerà la dichiarazione Expression <> quando si desidera trattare l'espressione lambda come dati.

Perché vuoi farlo?

Ecco una citazione dal Linq Libro In Azione,

"Espressione alberi possono essere date a strumenti in fase di esecuzione, che li usano per guidare loro esecuzione o li traducono in qualcosa d'altro, come ad esempio SQL nel caso di LINQ to SQL."

L'utilizzo di Expression Trees consente di prendere l'espressione lambda e convertirla in dati, così funziona Linq to SQL, accetta l'espressione lambda o esegue query sugli operatori o sulle espressioni di query e li converte in SQL. visualizza e modifica l'albero di espressioni creato una volta convertito in sql.

+0

Ok, questo mi aiuta a capire questo un po 'meglio. Posso capire perché il mio altro esempio che riguarda LINQ to SQL e un ritorno IQueryable da una tabella funzionerebbe con il tipo di ripetizione Expression now. – Loathian

0

Esiste un'enorme differenza tra Espressione e Func < ...>, Func è un delegato puro che è possibile richiamarlo direttamente, l'espressione è una struttura di dati valida informazioni su un'espressione come informazioni sull'espressione lambda o sintassi di Linq (ad es. da x nell'elenco dove x.Id = 1 seleziona x). L'espressione non può essere richiamata direttamente deve essere compilata per prima, le espressioni vengono utilizzate per convertire l'espressione da un modo a un altro l ike Link To Sql che converte un'espressione in istruzioni Sql, il modo migliore per fare ciò per cambiare il tipo di ritorno del metodo NameContains a Func insted of expression cuz stai lavorando con Linq To Objects, ma quando usi con Linq To Sql puoi usa sia Expression che func.