此代码正确地返回一行:
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where t.GetInterfaces().Contains(typeof(TInterface))
&& t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
select t);
}然而,当我使用PredicateBuilder时,我会得到零行:
var compiledPredicate = CompiledPredicate<TInterface>();
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where compiledPredicate.Invoke(typeof(TInterface))
select t);
}
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
// True means all records will be returned if no other predicates are applied.
var predicate = PredicateBuilder.True<Type>();
// Get types that implement the interface (T).
predicate = predicate.And(t => t.GetInterfaces().Contains(typeof(T)));
// If the config file includes filtering by base class, then filter by it.
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
predicate = predicate.And(t => t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`'));
}
return predicate.Compile();
}Someone suggested创建了循环变量的副本,但我尝试了,仍然得到零行。我不知道为什么使用PredicateBuilder不返回任何行。知道我错过了什么吗?
发布于 2013-12-10 17:55:55
您在注释(foundTypes.AddRange(x.GetTypes().AsQueryable().Where(compiledPredicate));)中提到的更改与您正在使用AsQueryable这一事实毫无关系。在第一种情况下,您将硬编码类型传递给谓词的每个调用,在第二种情况下,您将从序列中传递给定的项。如果您删除了AsQueryable并使用了Enumerable.Where,那么它也会工作,或者在调用它时传递当前项,而不是硬编码类型。
所以你可以简单地做:
foundTypes.AddRange(x.GetTypes().Where(compiledPredicate));此外,在创建谓词时,不需要像您所做的那样做那么多的工作。表达需要相当多的额外工作来处理。使用linq,您只需要处理委托,这些委托就不那么挑剔了。
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
Func<Type, bool> predicate = t => t.GetInterfaces().Contains(typeof(T));
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
return t => predicate(t) &&
t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`');
}
return predicate;
}https://stackoverflow.com/questions/20498961
复制相似问题