2010-03-16 7 views
5

Notez que _src hérite IQueryable<U> et que V hérite new();Problème de sélection de Linq C# dans la chaîne de méthode

J'ai écrit l'instruction suivante, il n'y a pas d'erreur de syntaxe.

IQueryable<V> a = from s in _src where (s.Right - 1 == s.Left) select new V(); 

Mais si je récrit comme suit, l'éditeur Visual Studio se plaint une erreur dans le "Select"

IQueryable<V> d = _src.Where(s => s.Right - 1 == s.Left).Select(s=> new V()); 

L'erreur est:

The type arguments cannot be inferred from the usage. Try specifying the type arguments explicitly. 
Candidates are: 
    System.Collections.Generic.IEnumerable<V> Select<U,V>(this System.Collections.Generic.IEnumerable<U>, System.Func<U,V>) (in class Enumerable) 
    System.Linq.IQueryable<V> Select<U,V>(this System.Linq.IQueryable<U>, System.Linq.Expressions.Expression<System.Func<U,V>>) (in class Queryable) 

Quelqu'un pourrait-il expliquer ce phénomène, et quelle est la solution pour corriger l'erreur?

=== Modifier (2010-03-16 17:35) ===

Merci Mike Deux. J'ai aussi essayé un exemple simple comme vous. Ca marche mais ça ne marche pas dans le mien. J'ai posté le code comme suit:

public class NSM<U, V> where U : IQueryable<U> where V : new() 
    { 
    private U _src; 
    public NSM(U source) { _src = source; } 
    public IQueryable<V> LeafNodes 
    { 
     get 
     { 
      return from s in _src where (s.Right - 1 == s.Left) select new V(); 
     } 
    } 
    } 

Je veux que les LeafNodes fonctionnent à réécrites dans la méthode de la chaîne de méthode LINQ. Une idée?

+0

Merci à tous. Quelle est l'affirmation équivalente du premier? – Gnought

+0

Ce code que vous avez ajouté ne sera compilé que si U est quelque chose qui a une propriété Right and Left. Donc, il ne peut pas seulement être un 'IQueryable ' sauf s'il y a un 'où U: ILeftRight' ou quelque chose. –

+0

Je l'ai compris grâce à votre échantillon mis à jour. Voir la mise à jour ci-dessous. Merci de fournir plus d'informations. –

Répondre

1

Quel est le type de _src? Est-ce qu'il met directement en œuvre IQueryable? Je demande parce que je peux obtenir un exemple simplifié de ce que vous montrez au travail.

IQueryable<int> ints = Enumerable.Range(4, 12).AsQueryable(); 

IQueryable<decimal> foo = from s in ints where s > 7 select s * 4.2m; 

IQueryable<decimal> bar = ints.Where(s => s > 7).Select(s => s * 4.2m); 

Ces deux sélections fonctionnent pour moi. Je pense que si le compilateur sait que ints (ou dans votre cas _src) est un IQueryable alors il appellera la surcharge correcte. Ou est-ce que je manque complètement quelque chose? Peut-être l'ai-je trop simplifié et j'ai perdu un peu de détail.

EDIT: Extension de ceci pour utiliser le nouvel exemple de code avec quelques modifications.

L'astuce est que Queryable.Select prend un Expression<Func<X, V>> et Enumerable.Select prend un Func<X,V> donc il vous suffit de fournir une version Expression à Select

Ou du code d'origine

Expression<Func<X,V>> expression = s => new V(); 
IQueryable<V> d = _src.Where(s => s.Right - 1 == s.Left).Select(expression); 
1

Les occurres d'erreur parce que le compilateur ne peut pas choisir les méthodes que vous voulez exécuter: méthode Select d'extension pour IEnumerable<T> ou Select méthode d'extension pour IQueryable<T>

1

Le problème que vous exécutez en est qu'il ya 2 différentes utilisations Sélectionnez dans votre deuxième exemple, et vous avez l'instruction using appropriée pour arriver à tous les deux. Le compilateur ne peut pas comprendre à partir de cette déclaration que vous voulez utiliser. Vous devez soit utiliser un appel plus spécialisé pour sélectionner ou supprimer une utilisation si elle n'est plus nécessaire, ou d'une manière ou d'une autre clarifier celui que vous voulez utiliser.

+0

Si j'ajoute "AsQueryable()" à la sélection comme suit: IQueryable d = _src.Where (s => s.Right - 1 == s.Left) .AsQueryable(). Sélectionnez (s => new V()); L'erreur est également la même. – Gnought

0

Pour résoudre le ambiguïté pour le compilateur utiliser la fonction AsEnumerable()

src.AsEnumerable().Select(s => new V()); 

Ou assigner à IQueryable

IQueryable<V> x = src.AsEnumerable().Select(s => new V()).AsQueryable(); 
+0

Mais cela retournera IEnumerable plutôt que IQueryable . Quelle est la solution sans changer le type de retour? – Gnought

+0

@Gnought Je l'ajoute à l'édité le poste. – Cornelius

+0

remercie votre essai. – Gnought