Avoid Code Repeat When Using LINQ

So, I have several methods that look like this: - which sorts the list by artist, album, year, etc.

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

and this:

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

Now, obviously, this is not good code, so it needs to be reorganized into one Sort () method, but I just can’t figure out how to do this in the easiest way. I don't care if it uses IComparer or LINQ.

I want it to look something like this:

  public void Sort(SortOrder sortOrder, SortType sortType) { //implementation here } public enum SortType { Artist, Album, Year } 

So what is the cleanest way to do this without repeating the code?

Thanks Lee

+6
c # linq refactoring
source share
4 answers

You can transfer the signature of the OrderBy extension method:

Update 1 , you must be explicit in the first generic parameter for your Selector Func key. I'm going to guess your type and name it "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(); } } 

Now you can call "Sort" as follows:

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

Update 2

Comment on Tom Lokhorst: If you want to predefine some sorting criteria, you can do this by specifying a class as follows:

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

Now you can just call:

 Sort(SortOrder.Descending, SortColumn.Artist); 
+12
source share

You can try using a common comparator .

+2
source share

It seems that sorting takes life if you have several methods dedicated to this. Maybe they can be put together in class.

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

Here's a usage example:

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

Conclusion: Paul, John, Ringo, George.

0
source share

I think you should add an extension method to 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(); } } } 

and then you can use it nicely with each of your objects:

 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 already exists:

 using System.Data.SqlClient; 
0
source share

All Articles