2009-01-27 18 views
6

Ok, así que tengo una serie de métodos que se parecen a esto: - la cual ordena una lista por artista, álbum, año, etc.Evitar la repetición de código cuando se utiliza 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(); 
     } 

y esto:

 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(); 
     } 

Ahora, obviamente, este no es un buen código, por lo que necesita una refactorización en un método Sort(), pero no puedo encontrar la forma de hacerlo de la manera más simple posible. No me importa si usa IComparer o LINQ.

que quiere que se vea algo como esto:

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

    public enum SortType 
    { 
     Artist, 
     Album, 
     Year 
    } 

Así que cuál es la forma más limpia de hacer esto sin la repetición de código?

Gracias, Lee

Respuesta

12

Usted debe ser capaz de imitar la firma del método de extensión OrdenarPor:

Actualización 1 que tiene que ser explícita en el primer parámetro genérico a su keySelector Func. Voy a adivinar tu tipo y llamarlo "Canción".

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(); 
    } 
} 

Ahora se puede llamar "Ordenar" de esta manera:

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

Actualización 2

Siguiendo con el comentario de Tom Lokhorst: Si desea predefinir algunos criterios de clasificación de la taquigrafía, se podría hacerlo definiendo una clase como esta:

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

ya se puede llamar simplemente:

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

Además, si usted, por alguna razón, no desea anotar el lambda explícito en la llamada a 'Ordenar' (coul d obtener grande), puede crear algún tipo de lista con objetos 'Func ' predefinidos (equivalente a la enumeración en el ejemplo). –

+0

Divertido Lo leí esta misma mañana en el libro de Linq in Action –

+0

Los argumentos de tipo para el método 'System.Linq.Enumerable.OrderByDescending (System.Collections.Generic.IEnumerable , System.Func ) 'no se puede inferir del uso. Intente especificar los argumentos de tipo explícitamente. En las líneas orderby y orderbyDesc. –

0

Parece que la clasificación está cobrando vida si tiene varios métodos dedicados a ella. Tal vez puedan reunirse en una clase.

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; 
    } 
} 

Aquí hay ejemplos de uso:

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); 
} 

salida es Paul, John, Ringo, George.

0

creo que se debe añadir un método de extensión a 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(); 
      } 
    } 
} 

y entonces usted puede utilizar casi con cada una de sus objetos:

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 ya existe:

using System.Data.SqlClient; 
Cuestiones relacionadas