![](/img/trans.png)
[英]Using IEnumerable<T> and IQueryable<T> in a generic repository
[英]Generic method for both IEnumerable<T> and IQueryable<T>
我試圖制作一種用於分頁IEnuemrable<T>
和IQueryable<T>
的通用方法
像這樣:
public T Paginate<T, TS>(T list) where T : IEnumerable<TS>
{
CheckValidityAndClamp();
return (T)(list.Skip(Page*PageSize).Take(PageSize));
}
當我傳入List<int>
實例時,它可以正常編譯。 但是運行時會給出強制轉換異常:
System.InvalidCastException : An object of type '<TakeIterator>d__3a`1[System.Int32]' can not be converted to the type 'System.Collections.Generic.List`1[System.Int32]'.
這是為什么? List<int>
實現IEnumerable<int>
那么為什么要強制轉換異常?
您沒有返回列表。 Take
是通過迭代器塊實現的,這意味着實際類型是沒有編譯時標識符的類型(這就是為什么看起來如此奇怪的原因),並且它實現了IEnumerable
。 它不是List
,您試圖將其投射到。
最重要的是,您的方法實際上不適用於任何IQueryable
對象。 它正在調用Skip
的實現,該實現接受IEnumerable
(因為這是通用約束告訴編譯器必須實現的內容),因此,如果它是IQueryable
(即使您解決了雜亂的轉換問題),也就不會使用查詢提供程序翻譯Skip
呼叫。 您需要在這里有兩個重載,一個用於IQueryable
,一個用於IEnumerable
; 鑒於您需要調用兩個Skip
and Take
方法,而IEnumerable
和IQueryable
分別調用兩個方法,因此這幾乎是問題固有的。
為了擴展Servy(正確)的答案-另一個問題是Skip
和Take
是擴展方法,這是調用靜態方法的語法糖。 由於靜態方法是在編譯時綁定的,因此編譯器擁有的最佳信息是T
是IEnumerable<TS>
,因此編譯器將Skip
and Take
綁定到Enumerable
的靜態方法。 無法在運行時動態綁定靜態方法。 這就是為什么IEnumerable
和IQueryable
( Enumerable
和Queryable
)的擴展方法有兩種不同的類的原因
您需要兩個重載。
由於無法將IEnumerable強制轉換為List,因此得到此信息(這就是LINQ具有.ToList()擴展名的原因)。 我認為您想要的是這樣的:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
它將與實現IEnumerable的任何源一起工作(List,T [],IQueryable)
然后可以這樣稱呼它:
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
正如其他答案中指出的那樣。 IQueryable有它自己的擴展方法集。 因此盡管這一切都會起作用,但分頁將不會作為數據源進行,因為它將使用IEnumerable擴展
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.