2015-08-28 98 views
1

我目前正在摆弄通用存储库。我的测试应用程序使用C#。我做了一个函数,打印出特定存储库中的所有项目。存储库是输入参数。整个块是在这个岗位的底部,目前本身的功能如下:Ordeby(),Where()等用于具有泛型类型的函数

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

它工作正常,但它缺少的东西像一类的特定属性排序,如LastNamePersonProductNameProduct。我想知道是否可以发送一个额外的参数到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 Expression中将它们用于例如排序,过滤集合。

感谢


下面是我的代码片段。我剪掉了不重要的部分。

主程序

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

回答

2

是的,你可以使用委托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>类型的参数,该过程是相同的如上。

注意:如果您使用ORM(例如EF),ORM需要整个表达式树来构建查询的SQL语句。当我们传递一个委托时,所以排序或过滤不会转换为SQL。 ORM加载数据,然后对其应用排序或筛选。

如果你想确保他们转换为SQL,返回类型必须是实现IQueryable类型和函数的参数应更改为Expression<Func<T,TOrder>>orderByExpression<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(); 

比定义参数更灵活,自然为函数中的每个功能。

+0

我的最终目标是与EF和ORM合作。感谢编辑。至于'Func <>'我完全忘记了我可以使用这个委托。耻辱:p – Celdor

+0

难以按照我选择的方式更改此功能,以便进行排序,筛选或排序?这可能是另一个问题的话题。 – Celdor

+0

没有那么难,你可以添加任何你想要的参数,然后根据它们来决定,但是我认为我添加到我的答案中的建议是一个更好的选择。 –

相关问题