【问题标题】:How to OrderBy on a generic IEnumerable (IEnumerable<T>) using LINQ in C#?如何在 C# 中使用 LINQ 对通用 IEnumerable (IEnumerable<T>) 进行 OrderBy?
【发布时间】:2010-05-05 06:05:05
【问题描述】:

在我的通用存储库中,我有以下方法:

public virtual IEnumerable<T> GetAll<T>() where T : class
{
    using (var ctx = new DataContext())
    {
        var table = ctx.GetTable<T>().ToList();
        return table;
    }
}

T 是一个 Linq to Sql 类,我希望能够对特定属性(即 int SortOrder)进行 OrderBy。假设 T 具有属性名称“SortOrder”,然后对该属性执行 OrderBy。但我不确定如何实现这一目标。所以我需要一些帮助。谢谢!我觉得动态语言在做这类工作时真的很出色!

Quote from ScottGu:

在编写类型安全查询时 非常适合大多数情况,有 您需要灵活性的情况 动态构建查询 苍蝇

这正是我面临的问题,我想知道这个 linq 动态帮助器是否可以制作成官方的 .NET 库。

【问题讨论】:

标签: c# linq sql-order-by generic-list


【解决方案1】:
public IEnumerable<T> GetAll<T,K>(Expression<Func<T,K>> sortExpr)
{
  using (var ctx = new DataContext())
  {
    ctx.ObjectTrackingEnabled = false;
    var table = ctx.GetTable<T>().OrderBy(sortExpr).ToList();
    return table;
  }
}

用法:

var t = GetAll<Foo, int>(x => x.Bar);

很遗憾,您必须提供密钥的类型。除非你开始搞乱表达式。

【讨论】:

    【解决方案2】:

    要使其工作,您需要定义一个约束。例如:

    public interface IOrderable
    {
        int SortOrder { get; }
    }
    
    public virtual IEnumerable<T> GetAll<T>() where T : class, IOrderable
    {
        ...
    }
    

    现在您可以在方法体内使用ts.OrderBy(t =&gt; t.SortOrder)。然后,您打算与此方法一起使用的所有类都必须实现此接口。

    但是,正如您指出的 LINQ To SQL 类不实现此接口。如果使用 LINQ to SQL,我建议您不要采用这种方法。使用 LINQ to SQL,从表中获取所有对象已经非常容易,并且有一种简单的方法可以对这些对象进行排序。如果您学会正确使用所提供的接口,您的查询也会更快并使用更少的内存,因为您让数据库为您进行过滤而不是在客户端进行过滤。

    【讨论】:

      【解决方案3】:

      一般不能这样做,除非将类型参数T 限制为具有要排序的属性的类型。例如,如果你有一个名为IHaveTheProperty 的接口,那么你可以这样做:

      public virtual IEnumerable<T> GetAll<T>() where T : class, IHaveTheProperty
      {
          using (var ctx = new DataContext())
          {
              ctx.ObjectTrackingEnabled = false;
              var table = ctx.GetTable<T>().ToList().AsReadOnly().OrderBy(t=>t.TheProperty);
              return table;
          }
      }
      

      但是没有约束,只能使用System.Object类型的方法。


      LINQ to SQL 类创建partial。这意味着您可以创建另一个类部分来强制其中一个类实现您的接口:

      public partial class Address : IHaveTheProperty
      {
      }
      

      【讨论】:

      • 这意味着我的所有 linq to sql 类都需要具有 SortOrder 来实现 IHaveTheProperty 接口?
      • 另一个问题是如何传入实现 IHaveTheProperty 的 T?因为 GetAll 是通用的并且被全面使用,所以一些 T 类型不会有 SortOrder 属性。所以看起来我需要有 2 个 GetAll 方法(1 表示有 SortOrder T 类型 1 表示没有),但这是我试图避免的。
      • 任何时候泛型方法使用一个类成员,它必须被限制在具有该成员的类型集合中。这可以通过约束到接口或约束到基类来完成,但必须这样做。如果您有一些带有特定成员的 T 和一些没有特定成员的 T,那么您需要两个具有不同约束的独立泛型方法。
      【解决方案4】:

      您可以使用动态 Linq 库来动态构建 OrderBy:http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

      就我个人而言,我总是让我的存储库返回 IQueryable,然后消费者可以根据需要处理构建额外的过滤、排序或投影。

      【讨论】:

        【解决方案5】:

        如果我被要求这样做,我可以这样做:

        public virtual IEnumerable<T> GetAll<T>() where T : class
        {
            using (var ctx = new DataContext())
            {
                var table = ctx.GetTable<T>().ToList();
                return table;
            }
        }
        

        publuc virtual IEnumerable<T> GetAll<T>(Func<T,bool> orderByClause) where T:class{
        
        return GetAll<T>().OrderBy(orderByClause);
        }
        

        或在 .net 4 中使参数可选,并在单个方法中完成相同的操作。您将需要一个类似于逻辑的谓词构建器来帮助您的客户端代码动态构建委托。杰弗里在我的评论上的链接有点说明了所有这些东西!简而言之,这个来自 C#3.0 扩展材料的link 也很酷!如果您需要快速编写代码,他们甚至有这个LinqKit

        【讨论】:

          【解决方案6】:

          这应该可以解决问题:

          myEnumeration.OrderBy( itm => itm.SortOrder )
          

          【讨论】:

          • 我认为这不会起作用,因为我们不知道它的类型,因此不会解析 .property。
          猜你喜欢
          • 1970-01-01
          • 2012-09-17
          • 1970-01-01
          • 2010-09-07
          • 2023-03-14
          • 2017-11-21
          • 2012-01-28
          相关资源
          最近更新 更多