Как 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 )