子集合的表达式列表 .Any

我正在使用表达式树构建genericslinq查询。 在子集合上创建表达式时,我陷入困境。 由于类型不兼容,方法调用会爆炸。 通常我知道要放在那里,但Any()方法调用让我感到困惑。 我尝试了所有我能想到的类型而且没有运气。 任何帮助,将不胜感激。

这是我的实体类:

public class Story : Entity { public string Author { get; set; } public IList Contributors { get; set; } } 

我要生成表达式树的查询:

 var stories = new List(); stories.Where(p => p.Author.Contains("Test") || p.Contributors.Any(c => c.Contains("Test"))); 

到目前为止我得到了什么

 public interface IFilterCriteria { string PropertyToCompare { get; set; } object ValueToCompare { get; set; } FilterOperator FilterOperator { get; set; } bool IsList { get; set; } Expression Expression { get; set; } } public static IQueryable Filter(this IQueryable query, IList filterCriterias, LogicalOperator logicalOperator = LogicalOperator.And) { if (filterCriterias != null && filterCriterias.Any()) { var resultCondition = filterCriterias.ToExpression(query, logicalOperator); var parameter = Expression.Parameter(query.ElementType, "p"); if (resultCondition != null) { var lambda = Expression.Lambda(resultCondition, parameter); var mce = Expression.Call( typeof(Queryable), "Where", new[] { query.ElementType }, query.Expression, lambda); return query.Provider.CreateQuery(mce); } } return query; } public static Expression ToExpression(this IList filterCriterias, IQueryable query, LogicalOperator logicalOperator = LogicalOperator.And) { Expression resultCondition = null; if (filterCriterias.Any()) { var parameter = Expression.Parameter(query.ElementType, "p"); foreach (var filterCriteria in filterCriterias) { var propertyExpression = filterCriteria.PropertyToCompare.Split('.').Aggregate(null, (current, property) => Expression.Property(current ?? (parameter as Expression), property)); Expression valueExpression; var constantExpression = Expression.Constant(filterCriteria.ValueToCompare); if (!filterCriteria.IsList) { valueExpression = Expression.Convert(constantExpression, propertyExpression.Type); } else { valueExpression = Expression.Call(typeof (Enumerable), "Any", new[] {typeof (string)}, propertyExpression, filterCriteria.Expression, Expression.Constant(filterCriteria.ValueToCompare, typeof (string))); } Expression condition; switch (filterCriteria.FilterOperator) { case FilterOperator.IsEqualTo: condition = Expression.Equal(propertyExpression, valueExpression); break; case FilterOperator.IsNotEqualTo: condition = Expression.NotEqual(propertyExpression, valueExpression); break; case FilterOperator.IsGreaterThan: condition = Expression.GreaterThan(propertyExpression, valueExpression); break; case FilterOperator.IsGreaterThanOrEqualTo: condition = Expression.GreaterThanOrEqual(propertyExpression, valueExpression); break; case FilterOperator.IsLessThan: condition = Expression.LessThan(propertyExpression, valueExpression); break; case FilterOperator.IsLessThanOrEqualTo: condition = Expression.LessThanOrEqual(propertyExpression, valueExpression); break; case FilterOperator.Contains: condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression); break; case FilterOperator.StartsWith: condition = Expression.Call(propertyExpression, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }), valueExpression); break; case FilterOperator.EndsWith: condition = Expression.Call(propertyExpression, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }), valueExpression); break; default: condition = valueExpression; break; } if (resultCondition != null) { switch (logicalOperator) { case LogicalOperator.And: resultCondition = Expression.AndAlso(resultCondition, condition); break; case LogicalOperator.Or: resultCondition = Expression.OrElse(resultCondition, condition); break; } } else { resultCondition = condition; } } } return resultCondition; } 

这就是我使用表达式的方式:

 var stories = new List(); var filters = new List(); filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Author", FilterOperator = FilterOperator.Contains }); Expression<Func> func = t => t.Contains("Test"); filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Contributors", FilterOperator = FilterOperator.Contains, Expression = func }); stories.Filter(filters, LogicalOperator.Or).ToList(); 

但运行此代码后,我收到此错误,我无法解决

类型’System.Linq.Queryable’上没有generics方法’Any’与提供的类型参数和参数兼容。 如果方法是非generics的,则不应提供类型参数。 描述:执行当前Web请求期间发生未处理的exception。 请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

exception详细信息:System.InvalidOperationException:类型’System.Linq.Queryable’上没有generics方法’Any’与提供的类型参数和参数兼容。 如果方法是非generics的,则不应提供类型参数。

来源错误:

第184行:{第185行:
var overload = typeof(Queryable).GetMethods()。Single(mi => mi.Name ==“Any”&& mi.GetParameters()。Count()== 2); 第186行:
Expression.Call(typeof(可查询),“任何”,新[] {typeof(string)},propertyExpression或); 第187行:
valueExpression = Expression.Call(typeof(Enumerable),“Any”,new [] {typeof(string)},propertyExpression,或Expression.Constant(“Test”,

您不需要在代码中的Any位置调用Any方法。

你应该扩展Contains ,例如:

 case FilterOperator.Contains: // if collection if (propertyExpression.Type.IsGenericType && typeof(IEnumerable<>) .MakeGenericType(propertyExpression.Type.GetGenericArguments()) .IsAssignableFrom(propertyExpression.Type)) { // find AsQueryable method var toQueryable = typeof(Queryable).GetMethods() .Where(m => m.Name == "AsQueryable") .Single(m => m.IsGenericMethod) .MakeGenericMethod(typeof(string)); // find Any method var method = typeof(Queryable).GetMethods() .Where(m => m.Name == "Any") .Single(m => m.GetParameters().Length == 2) .MakeGenericMethod(typeof(string)); // make expression condition = Expression.Call( null, method, Expression.Call(null, toQueryable, propertyExpression), filterCriteria.Expression ); } else { condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression); } break; 

你也应该创建一个p参数( Expression.Parameter(query.ElementType, "p") ),否则你将获得variable 'p' of type 'WpfApplication2.Story' referenced from scope '', but it is not defined错误。

您可以将parameterFilter方法传递给ToExpression方法。