C# IEnumerable<;T>;和IQueryable<;T>;
我试图为C# IEnumerable<;T>;和IQueryable<;T>;,c#,generics,C#,Generics,我试图为IEnuemrable和IQueryable 像这样: public T Paginate<T, TS>(T list) where T : IEnumerable<TS> { CheckValidityAndClamp(); return (T)(list.Skip(Page*PageSize).Take(PageSize)); } public T分页(T列表),其中T:IEnumerable { 检查有效性和指示灯(); return(T)
IEnuemrable
和IQueryable
像这样:
public T Paginate<T, TS>(T list) where T : IEnumerable<TS>
{
CheckValidityAndClamp();
return (T)(list.Skip(Page*PageSize).Take(PageSize));
}
public T分页(T列表),其中T:IEnumerable
{
检查有效性和指示灯();
return(T)(list.Skip(Page*PageSize.Take(PageSize));
}
当我传入一个列表
实例时,它编译得很好。
但运行时会出现强制转换异常:
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]'.
System.InvalidCastException:类型为“d_u3a`1[System.Int32]”的对象无法转换为类型为“System.Collections.Generic.List`1[System.Int32]”。
为什么呢?
List
实现了IEnumerable
,那么为什么会出现强制转换异常?您没有返回列表Take
是用迭代器块实现的,这意味着实际类型是一个没有编译时标识符的类型(这就是为什么它看起来很奇怪),并且它实现了IEnumerable
。它不是您试图将其强制转换到的列表
除此之外,您的方法实际上无法用于任何IQueryable
对象。它调用Skip
的实现,该实现接受IEnumerable
(因为这是泛型约束告诉编译器它必须实现的),因此如果它是IQueryable
(即使解决了混乱的cast问题),也不会使用查询提供程序来翻译Skip
调用。这里需要有两个重载,一个用于IQueryable
,另一个用于IEnumerable
;考虑到您需要调用两个Skip
和Take
方法,一个用于IEnumerable
和IQueryable
您没有返回列表,这是问题的本质Take
是用迭代器块实现的,这意味着实际类型是一个没有编译时标识符的类型(这就是为什么它看起来很奇怪),并且它实现了IEnumerable
。它不是您试图将其强制转换到的列表
除此之外,您的方法实际上无法用于任何IQueryable
对象。它调用Skip
的实现,该实现接受IEnumerable
(因为这是泛型约束告诉编译器它必须实现的),因此如果它是IQueryable
(即使解决了混乱的cast问题),也不会使用查询提供程序来翻译Skip
调用。这里需要有两个重载,一个用于IQueryable
,另一个用于IEnumerable
;考虑到您需要调用两个Skip
和Take
方法,这是问题的本质,一个用于IEnumerable
和IQueryable
来扩展Servy(正确)的答案-另一个问题是Skip
和Take
是扩展方法,这是调用静态方法的语法糖。由于静态方法是在编译时绑定的,编译器拥有的最佳信息是T
是IEnumerable
,因此编译器将Skip
和Take
绑定到可枚举的静态方法。无法在运行时动态绑定静态方法。这就是为什么在IEnumerable
和IQueryable
上有两个不同的扩展方法类(Enumerable
和Queryable
)
您需要两个重载。来扩展Servy(正确)的答案-另一个问题是Skip
和Take
是扩展方法,这是调用静态方法的语法糖。由于静态方法是在编译时绑定的,编译器拥有的最佳信息是T
是IEnumerable
,因此编译器将Skip
和Take
绑定到可枚举的静态方法。无法在运行时动态绑定静态方法。这就是为什么在IEnumerable
和IQueryable
上有两个不同的扩展方法类(Enumerable
和Queryable
)
您需要两个重载。由于无法将IEnumerable强制转换为List(这就是为什么LINQ具有.ToList()扩展名)。我想你想要的是这样的:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
public IEnumerable分页(IEnumerable列表)
{
返回列表。跳过(页面*页面大小)。获取(页面大小);
}
它将与实现IEnumerable(List,T[],IQueryable)的任何源一起使用
你可以这样称呼它:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
IEnumerable list=someQueryResult;
IEnumerable page=class.Paginate(列表);
正如其他答案所指出的那样。IQueryable有自己的一组扩展方法。因此,尽管这样做可行,但分页不会作为数据源进行,因为它将使用IEnumerable扩展名,因为无法将IEnumerable强制转换为List(这就是为什么LINQ具有.ToList()扩展名)。我想你想要的是这样的:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
public IEnumerable分页(IEnumerable列表)
{
返回列表。跳过(页面*页面大小)。获取(页面大小);
}
它将与实现IEnumerable(List,T[],IQueryable)的任何源一起使用
你可以这样称呼它:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
IEnumerable list=someQueryResult;
IEnumerable page=class.Paginate(列表);
正如其他答案所指出的那样。IQueryable有自己的一组扩展方法。因此,尽管这一切都会起作用,但分页不会作为数据源进行,因为它将使用IEnumerable扩展名您可以显示调用代码吗?您可以显示调用代码吗?它将进行编译,但不会绑定到IQueryable
扩展方法。我已经更新,使它更清楚,但它将编译和运行。但它不会非常有效,因为它会减少