我有一个实现接口的类,我需要返回一个Queryable<>给定某个Where谓词的那个接口的列表:
public interface ISomeInterface
{
int ID{get;}
IQueryable<ISomeInterface> GetWhere(Func<ISomeInterface,bool> predicate);
}
public class SomeClass : ISomeInterface
{
public static IQueryable<SomeClass> AVeryBigList;
public int ID {get;set;}
public IQueryable<ISomeInterface> GetWhere(Func<ISomeInterface,bool> predicate)
{
return (from m in AVeryBigList select m).Where(predicate);
}
}
问题是,这甚至不会编译,因为谓词不匹配。
到目前为止我已尝试过:
return (from m in AVeryBigList select m as ISomeInterface)
.Where(predicate);
这将编译,但会在运行时失败,说它无法实例化接口
第二次尝试:
return (from m in AVeryBigList select m)
.Cast<ISomeInterface>
.Where(predicate);
这将失败并出现更神秘的错误:无法将“System.Linq.Expressions.MethodCallExpression”类型的对象强制转换为“SubSonic.Linq.Structure.ProjectionExpression”。
修改
wcoenen 的答案可行。当我的AVeryBigList由SubSonic 3.0提供时,现在出现问题。在使用Cast&lt;&gt;:
执行查询时,我从SubSonic中抛出异常Unable to cast object of type 'System.Linq.Expressions.MethodCallExpression' to type 'SubSonic.Linq.Structure.ProjectionExpression'.
SubSonic.Linq.Structure.DbQueryProvider.Translate(Expression expression) at SubSonic.Core\Linq\Structure\DbQueryProvider.cs:line 203
我是否应该了解SubSonic的Linq不支持Cast&lt;&gt;或者这是SubSonic中的一个错误?
答案 0 :(得分:3)
Where
extension methods for IEnumerable确实采用了System.Func,这就是你试图在这里传递谓词的方式。
但是你正在使用IQueryable,而不是IEnumerable。 Where
extension methods for IQueryable采用System.Linq.Expressions.Expression,而不是System.Func。更改谓词参数的类型,如下所示:
IQueryable<ISomeInterface> GetWhere(Expression<Func<SomeClass, bool>> predicate)
{
return AVeryBigList.Where(predicate).Cast<ISomeInterface>();
}
或者,您可以保留原始函数声明并将谓词作为x => predicate(x)
传递给Where方法,但这会破坏IQueryable实现分析表达式和优化查询的能力。 (这正是Subsonic所做的那样;它分析表达式树以生成SQL语句。)
此外,您会很高兴听到.NET 4.0中不再需要.Cast<ISomeInterface>()
,因为对协方差的新支持。