2009-09-10 8 views
5

J'ai vu la fonction suivante dans un affichage qui permet de commander des données en utilisant une expression générique:Problème avec la fonction générique Linq OrderBy

public static IOrderedQueryable<T> OrderBy<T, TKey>(
    this IQueryable<T> source, Expression<Func<T, TKey>> func, bool isDescending) { 
    return isDescending ? source.OrderByDescending(func) : source.OrderBy(func); 
} 

Lorsque je tente d'utiliser cette fonction que je reçois une erreur « Le type ou le nom d'espace de noms « TKEY » n'a pas pu être trouvée (vous manque une directive à l'aide ou une référence d'assemblage?) » Je fais ici quelque chose de stupide, mais je ne peux pas le comprendre

Edit:..

Après avoir fait un peu plus de recherche, je pense que mon problème est de construire l'Expr ession que je passe dedans. Est-il possible de construire une expression pouvant contenir différents types? Disons que mon ensemble de données a une chaîne, un int, et un bool et je veux utiliser la fonction générique ci-dessus pour trier par l'un des éléments. Comment puis-je faire cela?

Je travaille maintenant ce:

if (IsString) 
{ 
    Expression<Func<T, string>> expString = ...; 
    // call orderBy with expString 
} 
else if (IsInt) 
{ 
    Expression<Func<T, int>> expInt; 
    // call orderBy w/ expInt 
} 
: 

Je veux quelque chose comme:

Expression<Func<T, {something generic!}>> exp; 
if (IsString) 
    exp = ...; 
else if (IsInt) 
    exp = ...; 
: 
// call orderBy with exp 
+0

Cela semble bien. Comment utilisez-vous cette méthode? L'avez-vous ajouté à une classe statique? – BFree

Répondre

2

Mon but était d'éliminer beaucoup de code répétitif. En plus de gérer l'ascendant/descendant, ma fonction "OrderBy" gère une autre logique commune. En supposant que la définition de la fonction dans l'affichage d'origine, on peut simplement faire ceci:

if ({need to sort by integer}) 
    query = OrderBy(objectT, a => a.myIntegerField, asc); 
else if ({need to sort by string}) 
    query = OrderBy(objectT, a=> a.myStringField, asc); 
: 
1

L'expression ne peut avoir un type; ma réponse ici préférée serait quelque chose comme:

IQueryable<T> query = ... 
if({case 1}) { 
    query = query.OrderBy(x=>x.SomeValue); 
} else if({case 2}) { 
    query = query.OrderBy(x=>x.SomeOtherValue); 
} ... 

Cependant, si vous voulez faire quelque chose de plus flexible, vous auriez probablement besoin d'entrer dans la coutume Expression écrit; quelque chose more like this.

+0

C'est ce que j'avais à l'origine, mais je me suis retrouvé avec une tonne de code "dupliqué" en raison du fait que j'ai beaucoup de champs et que j'ai besoin de gérer les tris ascendants/descendants. La réponse que j'ai posté semble bien fonctionner. – ejwipp

4

Une observation rapide: Vous avez vraiment pas besoin d'utiliser une expression lambda (Expression<Func<T,TKey>>). Un délégué simple (Func<T,TKey>) va bien.

Cela dit, je pense que la réponse que vous cherchez peut-être est le suivant:

Func<T,IComparable> func = null; 
if (IsString) 
    func = (T a) => a.SomeStringValue; 
else if (IsInt) 
    func = (T a) => a.SomeIntValue; 
// call orderBy with exp 
+0

Cela ressemble à ce que je cherchais. Cependant, j'ai joué un peu avec ça et je n'ai pas pu le compiler. Quand j'essaie de passer func dans une fonction OrderBy, le compilateur se plaint. Votre méthode serait légèrement plus propre si cela fonctionnait, mais malheureusement je ne peux pas y consacrer plus de temps maintenant. – ejwipp

+1

Quand vous avez le temps, dites-moi s'il vous plaît quelle est l'erreur du compilateur que vous voyez. – jpbochi

+0

Je suis finalement revenu à ça. Je pense que le problème est que dans ma fonction orderBy personnalisée, je fais un appel à ThenBy qui ne prend pas un argument Func - il nécessite l'expression lambda. – ejwipp

0

Jetez un oeil à this answer

Mon gestionnaire générique pour le tri est:

  • "dgvProcessList" est mon datagridview
  • "Process" est mon objet binded à elle
  • "e" est mon DataGridViewCellMouseEventArgs

      PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First(); 
         if (isSortedASC == true) 
          dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderByDescending(x => column.GetValue(x, null)).ToList(); 
         else 
          dgvProcessList.DataSource = ((List<Process>)dgvProcessList.DataSource).OrderBy(x => column.GetValue(x, null)).ToList(); 
    
         isSortedASC = !isSortedASC; 
         dgvProcessList.ClearSelection(); 
    

Cheers