Order By()、Where() 等在具有泛型类型的函数中使用
Ordeby(), Where(), etc. used in a function with generic types
我目前正在摆弄通用存储库。我的测试应用程序是在 C# 中。我做了一个函数,可以打印出特定存储库中的所有项目。存储库是输入参数。整个块位于此 post 的底部,目前函数本身如下所示:
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));
}
它工作正常,但它缺少某些东西,例如 class 中的特定 属性 排序,例如 Person
中的 LastName
或 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
}
目前,我不知道应该使用什么来测试字段和属性是否存在于 class 中。然后,如何在 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);
// ...
}
人的存储库
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);
}
}
是的,您可以,使用委托来按子句选择顺序:
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,return 类型必须是实现 IQueryable
的类型并且函数的参数应更改为 Expression<Func<T,TOrder>>
对于 orderBy
和 Expression<Func<T,bool>>
对于 while
.
建议
将此方法定义为 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();
这比在函数中为每个功能定义参数更加灵活和自然。
我目前正在摆弄通用存储库。我的测试应用程序是在 C# 中。我做了一个函数,可以打印出特定存储库中的所有项目。存储库是输入参数。整个块位于此 post 的底部,目前函数本身如下所示:
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));
}
它工作正常,但它缺少某些东西,例如 class 中的特定 属性 排序,例如 Person
中的 LastName
或 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
}
目前,我不知道应该使用什么来测试字段和属性是否存在于 class 中。然后,如何在 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);
// ...
}
人的存储库
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);
}
}
是的,您可以,使用委托来按子句选择顺序:
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,return 类型必须是实现 IQueryable
的类型并且函数的参数应更改为 Expression<Func<T,TOrder>>
对于 orderBy
和 Expression<Func<T,bool>>
对于 while
.
建议
将此方法定义为 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();
这比在函数中为每个功能定义参数更加灵活和自然。