[英]Ordeby(), Where(), etc. used in a function with generic types
I am currently fiddling with generic repositories. 我目前在摆弄通用存储库。 My test application is in C#. 我的测试应用程序在C#中。 I have made a function that prints out all items in particular repository. 我做了一个可以打印出特定存储库中所有项目的函数。 A repository is an input parameter. 存储库是输入参数。 The whole block is at the bottom of this post and currently the function itself looks like this: 整个代码块在本文的底部,当前函数本身如下所示:
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));
}
It's working fine but it's missing things like ordering by particular property in a class, such as LastName
in Person
or ProductName
in Product
. 它工作正常,但缺少诸如按类中的特定属性排序的功能,例如Person
LastName
或Product
ProductName
。 I was wondering if it's possible to send an extra parameter to PrintCollection<T, TKey>(...)
and test whether the particular field exists and then order by it. 我想知道是否有可能将额外的参数发送给PrintCollection<T, TKey>(...)
并测试特定字段是否存在,然后对其进行排序。 For instance: 例如:
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
}
At the moment, I don't know what I should use to test the fields and properties against their existance in a class. 目前,我不知道应该使用什么来测试字段和属性是否存在于类中。 And then, how to use them in LINQ and Lambdsa Expression to eg order, sort, filter collections. 然后,如何在LINQ和Lambdsa Expression中使用它们,例如对集合进行排序,排序和过滤。
Thanks 谢谢
Main program 主程序
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);
}
}
Interface IRepository
接口IRepository
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);
}
}
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); } }
Repository for Products 产品资料库
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); } }
Yes, you can, using delegate for selecting order by clause: 是的,您可以使用委托来选择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));
}
you can call it like: 您可以这样称呼它:
PrintCollection(repo, x=>x.Name);
For Where
you need argument of type Func<T,bool>
and the process is the same as above. 对于Where
需要类型的参数Func<T,bool>
并且该过程是与上述相同。
Note: If you use ORM like EF, the ORMs need entire expression tree in order to build the SQL statement for the query. 注意:如果使用像EF这样的ORM,则ORM需要整个表达式树,以便为查询构建SQL语句。 As we pass a delegate, so the ordering or filtering does not translate to SQL. 当我们传递委托时,排序或过滤不会转换为SQL。 The ORM loads the data then applies ordering or filtering on it. ORM加载数据,然后对其进行排序或过滤。
If you want to make sure they translate to SQL, the return type must be of type that implements IQueryable
and the parameters for the function should change to Expression<Func<T,TOrder>>
for orderBy
and Expression<Func<T,bool>>
for while
. 如果要确保将它们转换为SQL,则返回类型必须是实现IQueryable
的类型,并且该函数的参数应针对orderBy
和Expression<Func<T,bool>>
更改为Expression<Func<T,TOrder>>
。 Expression<Func<T,bool>>
的while
。
Suggestion 建议
Define this method as extension for IEnumerable
: 将此方法定义为IEnumerable
扩展:
public static class IEnumerableExtenstions
{
static void PrintCollection<T>(this IEnumerable<T> collection)
{
foreach (T p in collection)
Console.WriteLine(Convert.ToString(p));
}
}
and then you can call it like: 然后可以这样称呼它:
repo.GetItems().Where(x=>x.Age>15).OrderBy(x=>x.Name).PrintCollection();
which is more flexible and natural than defining parameters for each functionality in the function. 这比为函数中的每个功能定义参数更加灵活自然。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.