order (), Where()等在泛型函数中使用
本文关键字:函数 泛型 Where order | 更新日期: 2023-09-27 18:10:16
我目前正在摆弄通用存储库。我的测试应用程序是在c#。我编写了一个函数,打印出特定存储库中的所有项目。存储库是一个输入参数。整个块位于这篇文章的底部,目前函数本身看起来像这样:
static void PrintCollection<T, TKey>(IRepository<T, TKey> repo)
{
// Error since compiler does not recognizes p.LastName
//foreach (Person p in repo.GetItems().OrderBy(p => p.LastName)) Console.WriteLine(Convert.ToString(p));
foreach (T p in repo.GetItems())
Console.WriteLine(Convert.ToString(p));
}
它工作得很好,但它缺少的东西,如按特定属性排序在一个类中,如LastName
在Person
或ProductName
在Product
。我想知道是否有可能向PrintCollection<T, TKey>(...)
发送一个额外的参数,并测试特定字段是否存在,然后按它排序。例如:
static void PrintCollection<T, TKey, TOrder>(IRepository<T, TKey> repo, TOrder o = default(TOrder))
{
if (o == default(TOrder))
foreach (T p in repo.GetItems()) Console.WriteLine(Convert.ToString(p));
else
// Order by o
}
目前,我不知道应该使用什么来测试字段和属性是否存在于类中。然后,如何在LINQ和Lambdsa表达式中使用它们来排序,排序,过滤集合。
感谢下面是我的代码片段。我把不重要的部分删掉了。
主程序
class Program
{
static void Main(string[] args)
{
PeopleRepository repPeople = new PeopleRepository();
ProductsRepository repProduct = new ProductsRepository();
PrintCollection(repPeople);
PrintCollection(repProduct);
}
static void PrintCollection<T, TKey>(IRepository<T, TKey> repo)
{
// Error since compiler does not recognizes p.LastName
//foreach (Person p in repo.GetItems().OrderBy(p => p.LastName)) Console.WriteLine(Convert.ToString(p));
foreach (T p in repo.GetItems()) Console.WriteLine(Convert.ToString(p));
}
}
IRepository
interface IRepository<T, TKey>
{
IEnumerable<T> GetItems();
T GetItem(TKey key);
// ...
}
Repository for People
class PeopleRepository : IRepository<Person, string>
{
private static List<Person> _proxy;
public PeopleRepository(List<Person> people = null)
{
if(people == null) _proxy = Person.GetAllPeople();
else _proxy = people;
}
public IEnumerable<Person> GetItems()
{
return _proxy;
}
public Person GetItem(string key)
{
return _proxy.SingleOrDefault(p => p.ID == key);
}
}
产品存储库
class ProductsRepository : IRepository<Product, int>
{
private static List<Product> _proxy;
public ProductsRepository(List<Product> products = null)
{
if (products == null) _proxy = Product.GetAllProducts();
else _proxy = products;
}
public IEnumerable<Product> GetItems()
{
return _proxy;
}
public Product GetItem(int key)
{
return _proxy.SingleOrDefault(p => p.ID == key);
}
}
可以,使用委托来选择order by子句:
static void PrintCollection<T, TKey, TOrder>(IRepository<T, TKey> repo,
Func<T,TOrder> orderBy)
{
var items = repo.GetItems();
if (orderBy != null)
items = items.OrderBy(orderBy);
foreach (T p in items)
Console.WriteLine(Convert.ToString(p));
}
你可以这样称呼它:
PrintCollection(repo, x=>x.Name);
对于Where
,需要Func<T,bool>
类型的参数,过程与上述相同。
注意:如果您使用像EF这样的ORM, ORM需要整个表达式树才能为查询构建SQL语句。当我们传递一个委托时,排序或筛选不会转换为SQL。ORM加载数据,然后对其应用排序或过滤。
如果您想确保它们转换为SQL,返回类型必须是实现IQueryable
的类型,并且函数的参数应该更改为orderBy
的Expression<Func<T,TOrder>>
和while
的Expression<Func<T,bool>>
。
将此方法定义为IEnumerable
的扩展:
public static class IEnumerableExtenstions
{
static void PrintCollection<T>(this IEnumerable<T> collection)
{
foreach (T p in collection)
Console.WriteLine(Convert.ToString(p));
}
}
然后你可以把它命名为:
repo.GetItems().Where(x=>x.Age>15).OrderBy(x=>x.Name).PrintCollection();
比为函数中的每个功能定义参数更灵活、更自然。