直接使用Linq表达式变量而不是lambda表达式时出错

时间:2013-06-25 16:08:32

标签: c# linq generics

我有以下代码从程序集中获取类型的集合,其中Type是一个类:

Assembly assembly = Assembly.LoadFile(DLLFile);
var types = assembly.GetTypes().AsEnumerable().Where(x => x.IsClass);

这正常并且符合预期。但是我想将lambda表达式拉出到Linq表达式变量(稍后将在此方法的参数中使用)。所以我做了以下事情:

private Expression<Func<Type, bool>> _standardFilter = (x => x.IsClass);
Assembly assembly = Assembly.LoadFile(DLLFile);
var types = assembly.GetTypes().AsEnumerable().Where(_standardFilter);

但是这不会编译错误:

System.Collections.Generic.IEnumerable<System.Type>' does not contain a 
definition for 'Where' and the best extension method overload  
'System.Linq.Enumerable.Where<TSource>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,int,bool>)' has some invalid arguments

我理解我的表达式不符合谓词System.Func<TSource,int,bool>,但是Where函数有一个带有System.Func<TSource,bool>谓词的重载,据我所知应该工作。

我尝试将assembly.GetTypes()(这是一个数组)的结果以多种方式转换为List,而不会帮助解决问题。

我还确保我已经获得了此课程的所有正确using语句,因为这似乎是Google搜索过程中遇到的一个问题。

过去我设法在IQueryable集合上使用了相同的技术,但我不明白为什么当Where函数在{{1}上可用时这不起作用收集并且应该接受我提供的谓词。

非常感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

将表达式编译为可执行代码(委托):

var types = assembly.GetTypes().AsEnumerable().Where(_standardFilter.Compile());

正如@Kirk所说,如果你不打算分析它,最好不要使用表达式树。只需使用Func<Type, bool>类型的过滤器。

答案 1 :(得分:2)

请注意,Enumerable扩展方法采用Func而不是Expression。所以你的论点输错了。

这与Entity Framework形成对比,后者采用Expression&lt; Func&gt;而不是普通的Func。

所以注意方法签名,它们是相似的,可以用相同的lambda调用,但实际上是不同的!

背后的原因是EF检查Expression并将其转换为SQL代码,而Linq to Object只是在内存中执行谓词。

答案 2 :(得分:0)

您可以尝试这样做:

private Func<Type, bool> standardFilter;
standardFilter = (type) => {
    return type.IsClass;
};

var types = assembly.GetTypes().AsEnumerable().Any(x => standardFilter(x));

然后您可以自由更改standardFilter的实现。只要它接收一个Type并返回bool是否应该包含它,它将保持模块化并完成我认为你想要的。