使用接口的Lambda Func委托

时间:2009-11-10 18:49:26

标签: linq subsonic

我有一个实现接口的类,我需要返回一个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中的一个错误?

1 个答案:

答案 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>(),因为对协方差的新支持。

相关问题