Как OrderBy для общего IEnumerable (IEnumerable <T>) с использованием LINQ в С#?

В моем общем хранилище у меня есть метод ниже:

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, и я хочу иметь возможность OrderBy для определенного свойства (т.е. int SortOrder). Скажем, если T имеет имя свойства "SortOrder", тогда выполните OrderBy в этом свойстве. Но я не уверен, как я могу это достичь. Поэтому мне нужны некоторые подсказки. Спасибо! Я чувствую, что динамические языки действительно светят при выполнении таких заданий!

Цитата от ScottGu:

При написании безопасных типов запросов отлично подходит для большинства сценариев, есть случаи, когда вам нужна гибкость динамически строить запросы на летать

И это именно та проблема, с которой я столкнулся, и мне интересно, можно ли включить этот динамический помощник linq в официальную библиотеку .NET.

Ответ 1

Вы можете использовать динамическую библиотеку Linq, которая позволит вам динамически строить OrderBy: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Лично у меня всегда есть мои репозитории, возвращающие IQueryable, тогда потребитель может обрабатывать дополнительную фильтрацию, упорядочивание или прогнозы по мере необходимости.

Ответ 2

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

К сожалению, вы должны указать тип ключа. Если вы не начнете возиться с выражениями.

Ответ 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
{
}

Ответ 4

Чтобы заставить это работать, вам нужно определить ограничение. Например:

public interface IOrderable
{
    int SortOrder { get; }
}

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

Теперь вы можете использовать ts.OrderBy(t => t.SortOrder) внутри тела метода. Все классы, которые вы собираетесь использовать с этим методом, должны затем реализовать этот интерфейс.

Однако, как вы указали, классы LINQ To SQL не реализуют этот интерфейс. Я бы рекомендовал, чтобы вы не применяли этот подход при использовании LINQ to SQL. С LINQ to SQL уже очень легко получить все объекты из таблицы, и есть простой способ упорядочить эти объекты. Если вы научитесь правильно использовать предоставленные интерфейсы, ваши запросы также будут намного быстрее и будут использовать меньше памяти, потому что вы получите базу данных для фильтрации вместо вас, а не для фильтрации на клиенте.

Ответ 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 сделать параметр необязательным и выполнить одно и то же в одном методе. Вам понадобится построитель предикатов, такой как логика, чтобы помочь вашим клиентам создавать сборку делегатов "на лету". Ссылка Джеффри на мой комментарий kinda иллюстрирует все это! И эта ссылка из расширенного материала из С# 3.0 в двух словах тоже крута! Если вам нужно быстро запустить код, у них даже есть LinqKit

Ответ 6

это должно сделать трюк:

myEnumeration.OrderBy( itm => itm.SortOrder )