【问题标题】:Avoiding code repetition when using LINQ使用 LINQ 时避免代码重复
【发布时间】:2009-01-27 22:16:24
【问题描述】:

好的,所以我有一些看起来像这样的方法:- 按艺术家、专辑、年份等对列表进行排序。

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

还有这个:

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

现在显然这不是好的代码,因此需要将其重构为一个 Sort() 方法,但我就是不知道如何以最简单的方式进行操作。我不在乎它使用的是 IComparer 还是 LINQ。

我希望它看起来像这样:

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

    public enum SortType
    {
       Artist,
       Album,
       Year
    }

那么在不重复代码的情况下,最简洁的方法是什么?

谢谢,李

【问题讨论】:

    标签: c# .net linq refactoring


    【解决方案1】:

    您应该能够模仿 OrderBy 扩展方法的签名:

    更新 1 您必须在 keySelector Func 的第一个通用参数中明确。我要猜测一下你的类型并称之为“歌曲”。

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

    现在你可以像这样调用“排序”了:

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

    更新 2

    跟进 Tom Lokhorst 的评论:如果您想预定义一些速记排序标准,可以通过定义这样的类来实现:

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

    现在您可以简单地调用:

    Sort(SortOrder.Descending, SortColumn.Artist);
    

    【讨论】:

    • 另外,如果您出于某种原因不想在调用 Sort 时写下显式 lambda(它可能会变大),您可以创建某种预定义的列表Func&lt;TSource, TKey&gt; 对象(相当于示例中的枚举)。
    • 有趣的是,我今天早上在 Linq in Action 一书中读到了这一点
    • 方法 'System.Linq.Enumerable.OrderByDescending(System.Collections.Generic.IEnumerable, System.Func)' 的类型参数不能是从用法推断。尝试明确指定类型参数。在 orderby 和 orderbyDesc 行上。
    • @Lee - 是在我几分钟前的编辑之前还是之后?我在测试后更改了代码并发现了同样的错误。
    • 是的,在我阅读您的更新之前,我已经修复了错误并且它工作得很好。谢谢马特。
    【解决方案2】:

    您可以尝试使用generic comparer

    【讨论】:

      【解决方案3】:

      我认为你应该给IList&lt;T&gt;添加一个扩展方法:

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

      然后你就可以在你的每一个对象上使用 pretty:

      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 已经存在:

      using System.Data.SqlClient;
      

      【讨论】:

        【解决方案4】:

        如果您有几种专用的方法,那么排序听起来就像它自己的生命一样。也许他们可以聚集成一个班级。

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

        以下是示例用法:

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

        输出是 Paul、John、Ringo、George。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-03-07
          • 1970-01-01
          • 1970-01-01
          • 2014-07-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多