簡體   English   中英

IEnumerable的通用方法 <T> 和IQueryable <T>

[英]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方法,而IEnumerableIQueryable分別調用兩個方法,因此這幾乎是問題固有的。

為了擴展Servy(正確)的答案-另一個問題是SkipTake是擴展方法,這是調用靜態方法的語法糖。 由於靜態方法是在編譯時綁定的,因此編譯器擁有的最佳信息是TIEnumerable<TS> ,因此編譯器將Skip and Take綁定到Enumerable的靜態方法。 無法在運行時動態綁定靜態方法。 這就是為什么IEnumerableIQueryableEnumerableQueryable )的擴展方法有兩種不同的類的原因

您需要兩個重載。

由於無法將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM