2010-12-13 26 views
2

OK, donc je l'ai écrit la fonction suivante:ne peut pas lancer de générique pour obtenir LINQ clause where

private IQueryable<LogEntry> SelectAll<T>(IEnumerable<LogEntry> logEntries, List<Expression<Func<LogEntry, bool>>> whereClause) 
{ 
    var selectAllQuery = from l in logEntries select l; 
    if (whereClause != null) 
    { 
     foreach (Expression<Func<LogEntry, bool>> whereStatement in whereClause) 
     { 
      selectAllQuery = selectAllQuery.Where(whereClause); 
     } 
    } 
} 

Mais il ne compilera pas. Il renvoie une erreur quand il essaie de retourner quelque chose à « selectAllQuery » comme suit:

System.Collections.Generic.IEnumerable » ne contient pas une définition pour « Où » et la meilleure surcharge de méthode d'extension System.Linq .Enumerable.Where (System.Collections.Generic.IEnumerable, System.Func) » a des arguments invalides

J'ai essayé ce casting dans tous les sens que je peux penser en vain. Dans le code ci-dessus, l'exécution de l'instruction select initiale renvoie selectAllQuery de type System.Linq.Enumerable.WhereSelectEnumerableIterator<LogEntry,LogEntry>

De toute évidence, il me manque quelque chose de fondamental à propos de LINQ. Mais quoi?

Cheers.

Répondre

5

Le problème est que selectAllQuery est un IEnumerable<LogEntry> et vous avez besoin d'un IQueryable<LogEntry> pour utiliser des arbres d'expression. Essayez simplement de changer la première ligne de la méthode:

var selectAllQuery = logEntries.AsQueryable(); 

Vous pouvez également compiler les prédicats que vous allez les obtenir sous forme de délégué:

foreach (Expression<Func<LogEntry, bool>> whereStatement in whereClause) 
{ 
    selectAllQuery = selectAllQuery.Where(whereStatement.Compile()); 
} 

EDIT: D'accord, les problèmes ne sont pas seulement parce que de Queryable, mais à cause de votre nom. Regardons cette déclaration foreach:

foreach (Expression<Func<LogEntry, bool>> whereStatement in whereClause) 
{ 
    selectAllQuery = selectAllQuery.Where(whereClause); 
} 

Vous n'utilisez pas whereStatement partout dans le corps de la boucle. Vous essayez d'appeler Where avec la liste complète des clauses à chaque itération. C'est là qu'une meilleure appellation aiderait. Essayez ceci, par exemple:

private IQueryable<LogEntry> SelectAll<T>(IEnumerable<LogEntry> logEntries, 
    List<Expression<Func<LogEntry, bool>>> filters) 
{ 
    var selectAllQuery = logEntries.AsQueryable(); 
    if (filters != null) 
    { 
     foreach (var filter in filters) 
     { 
      selectAllQuery = selectAllQuery.Where(filter); 
     } 
    } 
    return selectAllQuery; 
} 

Parce que le paramètre est maintenant pluralisé, il semble de toute évidence tort comme argument à la méthode Where - alors que la différence entre whereStatement et whereClause est pas tout évident comme le premier étant singulier et le dernier étant pluriel.

+0

Ouais, vous avez raison. – jason

+0

Eh bien, ni ne semble fonctionner. Il n'y a pas de méthode "Compile" disponible sur whereClause selon Intellisense, et en changeant le var en AsQueryable() je reçois toujours une erreur similaire - Erreur 'System.Linq.IQueryable ' ne contient pas de définition pour 'Où' et la meilleure méthode d'extension surcharge 'System.Linq.Enumerable.Where (System.Collections.Generic.IEnumerable , System.Func )' a certains arguments non valides. J'ai effectivement essayé le AsQueryable avant de poster comme il semblait la solution évidente. –

+0

@Matt: Désolé, cela aurait dû être 'whereStatement.Compile' - et si vous utilisiez 'whereStatement' dans le corps de la boucle dans le code original mais avec AsQueryable, cela aurait aussi fonctionné. Éditera avec les changements de nom suggérés ... –

1

Parfois, ce type d'erreur peut être résolu simplement en ajoutant System.Linq au projet ... et en le référant dans le fichier de classe. Très triste que VS IDE ne nous aide pas à résoudre dans le cadre du menu refactor ...