2015-08-28 20 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

沒有那麼難,你可以添加任何你想要的參數,然後根據它們來決定,但是我認爲我添加到我的答案中的建議是一個更好的選擇。 –

相關問題