2013-05-30 96 views
1

我有這樣的事情:C#泛型方法類型約束對幾類

public List<T> GetPageRows<T>(Expression<Func<T, bool>> predicate, List<ColumnSortOrder> sortOrder, int pageSize, int pageNo) where T : Type1, Type2, Type3 
    { 
     var filteredQueryable = GetRowsAndFilter(predicate); 
     var orderedQueryable = GetOrderedQueryable(sortOrder, filteredQueryable); 
     var pagedQueryable = orderedQueryable.Skip((pageNo - 1) * pageSize).Take(pageSize); 
     return pagedQueryable.ToList(); 
    } 

    private IQueryable<Type1> GetRowsAndFilter(Expression<Func<Type1, bool>> predicate) 
    { 
     return GetType1s(predicate); 
    } 

    private IQueryable<Type2> GetRowsAndFilter(Expression<Func<Type2, bool>> predicate) 
    { 
     return GetType2s(predicate); 
    } 

    private IQueryable<Type3> GetRowsAndFilter(Expression<Func<Type3, bool>> predicate) 
    { 
     return GetType3s(predicate); 
    } 

我希望,通過使GetRowsAndFilter()的非通用類特定版本,然後是制約GetPageRows泛型類型參數()分配給這三個類中的一個,編譯器能夠找出該做什麼。

但是where T : Type1, Type2, Type3似乎是非法的。

我該如何解決這個問題?

這個想法是,GetPageRows()中的算法是通用的,並且不依賴於我得到的特定類型的行。只有返回類型和謂詞取決於T.

編輯:我試圖約束他們的基類型和共同的空接口,但我仍然在var filteredQueryable = GetRowsAndFilter(predicate);中得到一個錯誤。 「無法解析方法」。它不知道如何選擇這些方法的正確版本。我不知道該怎麼辦。應該可以將實際類型T中的GetPageRows()中的一般算法與不同版本的GetRowsAndFilter()中的每個T的特定不同查詢分開。

+0

約束問題可以解決,但不幸的是,這不會解決後續的不可解析的方法調用問題。 –

+0

沒辦法解決這個問題呢?:( – pinkfloydhomer

+0

我想我可能會有一些東西,我已經修改了我的答案,但不確定它是否可行,並且可能會使代碼共享失去很多好處 –

回答

2

儘管您可以使用空接口指定一個約束來繞過多個約束,但這並不能解決您的問題:不能正確解析GetRowsAndFilter

彎曲代碼一點後,我想出了這個存根(我改變了切東西出去找它來編譯,但你應該能夠運用同樣的理念,你的代碼):

static void Main(string[] args) 
    { 
     var res = GetPageRows<Type1>(GetRowsAndFilter, t => true, null, 0, 0); 
     var res2 = GetPageRows<Type2>(GetRowsAndFilter, t => true, null, 0, 0); 

     Console.ReadLine(); 
    } 

    public static List<T> GetPageRows<T>(Func<Expression<Func<T, bool>>, IEnumerable<T>> getRows, Expression<Func<T, bool>> predicate, List<int> sortOrder, int pageSize, int pageNo) 
    { 
     var filteredQueryable = getRows(predicate); 
     return filteredQueryable.ToList(); 
    } 

    private static IEnumerable<Type1> GetRowsAndFilter(Expression<Func<Type1, bool>> predicate) 
    { 
     return Enumerable.Empty<Type1>(); 
    } 

    private static IEnumerable<Type2> GetRowsAndFilter(Expression<Func<Type2, bool>> predicate) 
    { 
     return Enumerable.Empty<Type2>(); 
    } 

    private static IEnumerable<Type3> GetRowsAndFilter(Expression<Func<Type3, bool>> predicate) 
    { 
     return Enumerable.Empty<Type3>(); 
    } 

您還需要提供方法來調用,否則編譯器無法解析它,因爲它沒有足夠的關於T的類型信息,通過提供方法並使其在方法簽名中使用相同的泛型類型,編譯器至少可以確保方法在談論相同的T。在呼叫方(GetPageRows<Type1>()),指定類型是剩下要正確解析的驅動程序。

0

明確指定這三種不同的類型在直覺上是錯誤的:您如何知道,在編譯時安全類型,您正在使用哪種類型?定義所有派生的公共基類或它們全部實現的接口,並將泛型參數類型約束爲該最小公分母。

+0

這三種類型已經從相同的基類,我也試着讓它們實現同一個空接口,問題是,如果我這樣做,仍然會在'var filteredQueryable = GetRowsAndFilter(predicate);'中得到錯誤,似乎無法選擇是否有另一種方法可以將GetPageRows中的算法與特定類型T分開,並將每種類型的特定查詢分別存放在特定版本的GetRowsAndFilter()中? – pinkfloydhomer

+0

是的,但是您需要在該基礎上進行約束類型或接口 - 它不會檢測到這三種類型共享一個基礎,並自動將該方法限制爲---它們,你需要告訴它。 –

+0

我已經這樣做了,它仍然失敗o 'GetRowsAndFilter(predicate);' – pinkfloydhomer

1

因爲在C#中多重繼承是不可能的,所以除非Type1,Type2Type3中的最多一個不是接口,否則不能這樣做。如果Type1,Type2,Type3中不止一個不是接口,則不可能滿足約束條件。另外,這些接口必須以類型約束的順序排列。

你可以說,等一下,如果Type3 : Type2 : Type1?在這種情況下,我們仍然可以有一個T,它可以滿足Type1而不是Type2Type3。所以在這種情況下,我們從編寫Type1, Type2, Type3,因爲它本身相當於Type3,我們從中得不到什麼。

+0

我想你的意思是寫「Type1,Type2和Type3中至多一個是_not_接口。」? –

+0

@FredrikMörk:是的。感謝您的更正! – jason