2009-01-27 11 views
6

Ok donc j'ai un certain nombre de méthodes qui ressemblent à ceci: - qui trie une liste par artiste, album, année, etc.éviter la répétition de code lors de l'utilisation LINQ

 public void SortByAlbum(SortOrder sortOrder) 
     { 
      if (sortOrder == SortOrder.Ascending) 
       _list = _list.OrderBy(x => x.Album).ToList(); 
      else if (sortOrder == SortOrder.Descending) 
       _list = _list.OrderByDescending(x => x.Album).ToList(); 
     } 

et ceci:

 public void SortByArtist(SortOrder sortOrder) 
     { 
      if (sortOrder == SortOrder.Ascending) 
       _list = _list.OrderBy(x => x.Artist).ToList(); 
      else if (sortOrder == SortOrder.Descending) 
       _list = _list.OrderByDescending(x => x.Artist).ToList(); 
     } 

Maintenant, évidemment, ce n'est pas bon code, donc il faut refactoriser en une méthode Sort(), mais je ne peux pas comprendre comment le faire de la manière la plus simple possible. Je m'en fiche si elle utilise IComparer ou LINQ.

Je veux qu'il ressemble à quelque chose comme ceci:

public void Sort(SortOrder sortOrder, SortType sortType) 
    { 
     //implementation here 
    } 

    public enum SortType 
    { 
     Artist, 
     Album, 
     Year 
    } 

donc ce qui est la plus propre façon de le faire sans répétition de code?

Merci, Lee

Répondre

12

Vous devriez être en mesure de mimer la signature de la méthode d'extension OrderBy:

Update 1 vous devez être explicite dans le premier paramètre générique à votre keySelector Func. Je vais deviner votre type et l'appeler "Song".

public void Sort<TKey>(SortOrder sortOrder, 
         Func<Song, TKey> keySelector) 
{ 
    if (sortOrder == SortOrder.Descending) 
    { 
     _list = _list.OrderByDescending(keySelector).ToList(); 
    } 
    else 
    { 
     _list = _list.OrderBy(keySelector).ToList(); 
    } 
} 

Maintenant, vous pouvez appeler "Trier" comme ceci:

Sort(SortOrder.Descending, x => x.Album); 

Mise à jour 2

Faisant suite au commentaire de Tom Lokhorst: Si vous voulez prédéfinir certains critères de tri sténographie, vous pourrait le faire en définissant une classe comme celle-ci:

public static class SortColumn 
{ 
    public static readonly Func<Song, string> Artist = x => x.Artist; 
    public static readonly Func<Song, string> Album = x => x.Album; 
} 

Maintenant, vous pouvez simplement appeler:

Sort(SortOrder.Descending, SortColumn.Artist); 
+0

Aussi, si pour une raison quelconque, vous ne voulez pas écrire le lambda explicite dans l'appel de 'Sort' d get big), vous pouvez créer une sorte de liste avec des objets prédéfinis 'Func ' (équivalent à l'énumération dans l'exemple). –

+0

Drôle je lis que ce matin dans le livre Linq in Action –

+0

Les arguments de type pour la méthode 'System.Linq.Enumerable.OrderByDescending (System.Collections.Generic.IEnumerable , System.Func ) 'ne peut être déduit de l'utilisation. Essayez de spécifier explicitement les arguments de type. Sur les lignes orderby et orderbyDesc. –

0

Les sons comme le tri prennent une vie propre si vous avez plusieurs méthodes qui lui sont dédiées. Peut-être qu'ils peuvent être rassemblés dans une classe.

public enum SortOrder 
{ 
    Ascending = 0, 
    Descending = 1 
} 
public class Sorter<T> 
{ 
    public SortOrder Direction { get; set; } 
    public Func<T, object> Target { get; set; } 
    public Sorter<T> NextSort { get; set; } 

    public IOrderedEnumerable<T> ApplySorting(IEnumerable<T> source) 
    { 
     IOrderedEnumerable<T> result = Direction == SortOrder.Descending ? 
      source.OrderByDescending(Target) : 
      source.OrderBy(Target); 

     if (NextSort != null) 
     { 
      result = NextSort.ApplyNextSorting(result); 
     } 
     return result; 
    } 

    private IOrderedEnumerable<T> ApplyNextSorting 
     (IOrderedEnumerable<T> source) 
    { 
     IOrderedEnumerable<T> result = Direction == SortOrder.Descending ? 
      source.ThenByDescending(Target) : 
      source.ThenBy(Target); 
     return result; 
    } 
} 

est ici Exemple d'utilisation:

List<string> source = new List<string>() 
    { "John", "Paul", "George", "Ringo" }; 

Sorter<string> mySorter = new Sorter<string>() 
{ 
    Target = s => s.Length, 
    NextSort = new Sorter<string>() 
    { 
     Direction = SortOrder.Descending, 
     Target = s => s 
    } 
}; 

foreach (string s in mySorter.ApplySorting(source)) 
{ 
    Console.WriteLine(s); 
} 

sortie est Paul, John, Ringo, George.

0

Je pense que vous devez ajouter une méthode d'extension à IList<T>:

public static class extIList { 
    public static IList<T> Sort<T, TKey>(this IList<T> list, SortOrder sortOrder, Func<T, TKey> keySelector) { 
      if (sortOrder == SortOrder.Descending) { 
       return list.OrderByDescending(keySelector).ToList(); 
      } else { 
       return list.OrderBy(keySelector).ToList(); 
      } 
    } 
} 

puis vous pouvez utiliser à peu près avec tous vos objets:

IList<Person> list = new List<Person>(); 

list.Add(new Person("David","Beckham")); 
list.Add(new Person("Gennaro","Gattuso")); 
list.Add(new Person("Cristian","Carlesso")); 

list = list.Sort(SortOrder.Descending, X => X.Name); 

ps SortOrder existe déjà:

using System.Data.SqlClient; 
Questions connexes