简体   繁体   English

如何在一个通用的IEnumerable(IEnumerable <T> )在C#中使用LINQ?

[英]How to OrderBy on a generic IEnumerable (IEnumerable<T>) using LINQ in C#?

In my generic repository I have below method: 在我的通用存储库中,我有以下方法:

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

T is a Linq to Sql class and I want to be able to OrderBy on a particular property (ie int SortOrder). T是Linq to Sql类,我希望能够在特定属性(即int SortOrder)上使用OrderBy。 Say if T has property name "SortOrder" then do OrderBy on this property. 假如T具有属性名称“SortOrder”,则在此属性上执行OrderBy。 But I am not sure how I can achieve this. 但我不确定如何实现这一目标。 So I need some helps. 所以我需要一些帮助。 Thank you! 谢谢! I feel like dynamic languages really shines in doing this kind of jobs! 我觉得动态语言在做这类工作时真的很棒!

Quote from ScottGu : 来自ScottGu的报价

While writing type-safe queries is great for most scenarios, there are cases where you want the flexibility to dynamically construct queries on the fly 虽然编写类型安全的查询对于大多数场景来说都很好,但在某些情况下,您希望能够灵活地动态构建查询

And this is exactly the problem I am facing and I am wondering if this linq dynamic helper can be made into official .NET library. 这正是我面临的问题,我想知道这个linq动态助手是否可以制作成官方的.NET库。

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

Usage: 用法:

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

Unfortunately, you have to supply the type of the key. 不幸的是,你必须提供密钥的类型。 Unless you start messing with the expressions. 除非你开始搞乱表达式。

You can't do it generically, unless you constrain the type parameter T to a type that has the property you want to sort on. 除非将类型参数T约束为具有要排序的属性的类型,否则不能一般地执行此操作。 For instance, if you have an interface named IHaveTheProperty , then you can do: 例如,如果您有一个名为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;
    }
}

But without a constraint, you can only use the methods of the System.Object type. 但是没有约束,您只能使用System.Object类型的方法。


LINQ to SQL classes are created partial . LINQ to SQL类是partial创建的。 That means that you can create another class part to force one of those classes to implement your interface: 这意味着您可以创建另一个类部件来强制其中一个类实现您的接口:

public partial class Address : IHaveTheProperty
{
}

To get this to work you would need to define a constraint. 要使其工作,您需要定义约束。 For example: 例如:

public interface IOrderable
{
    int SortOrder { get; }
}

public virtual IEnumerable<T> GetAll<T>() where T : class, IOrderable
{
    ...
}

Now you can use ts.OrderBy(t => t.SortOrder) inside the method body. 现在,您可以在方法体内使用ts.OrderBy(t => t.SortOrder) All the classes you intend to use with this method must then implement this interface. 您打算使用此方法的所有类必须实现此接口。

However as you pointed out LINQ To SQL classes do not implement this interface. 但是,正如您所指出的,LINQ To SQL类不实现此接口。 I would recommend that you do not take this approach if using LINQ to SQL. 如果使用LINQ to SQL,我建议您不要采用这种方法。 With LINQ to SQL it already is very easy to fetch all objects from a table and there is an easy way to order these objects. 使用LINQ to SQL,从表中获取所有对象非常容易,并且可以通过简单的方法来订购这些对象。 If you learn to use the provided interfaces correctly your queries will also be much faster and use less memory because you get the database to do filtering for you instead of filtering on the client. 如果您学会正确使用提供的接口,您的查询也会更快,并且使用更少的内存,因为您让数据库为您进行过滤而不是在客户端上进行过滤。

You could use the dynamic Linq library that would let you construct the OrderBy dynamically: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx 您可以使用动态Linq库来动态构建OrderBy: http ://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq- 动态查询library.aspx

Personally I always have my repositories return IQueryable then the consumer can handle building up additional filtering, ordering or projections as needed. 就个人而言,我总是让我的存储库返回IQueryable,然后消费者可以根据需要处理建立额外的过滤,排序或预测。

If I was asked to do this I could do something like this: 如果我被要求这样做,我可以这样做:

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

And

publuc virtual IEnumerable<T> GetAll<T>(Func<T,bool> orderByClause) where T:class{

return GetAll<T>().OrderBy(orderByClause);
}

or in .net 4 make the parameter optional and accomplish the same in a single method. 或者在.net 4中使参数可选,并在单个方法中完成相同的操作。 You will need a predicate builder like logic to help your client code build delegates on the fly. 您将需要一个类似逻辑的谓词构建器来帮助您的客户端代码动态构建委托。 The link by Jeffrey on my comment kinda illustrates all this stuff! 杰弗里对我评论的链接有点说明了所有这些内容! And this link from the extended material from C#3.0 in a nutshell is cool too! 简而言之,来自C#3.0的扩展材料的这个链接也很酷! If you need to crank the code quick they even have this LinqKit 如果你需要快速启动代码,他们甚至有这个LinqKit

这应该做的伎俩:

myEnumeration.OrderBy( itm => itm.SortOrder )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM