gpt4 book ai didi

c# - 子集合 List.Any 的表达式树

转载 作者:太空狗 更新时间:2023-10-29 23:23:10 28 4
gpt4 key购买 nike

我正在使用表达式树构建通用 linq 查询。在子集合上创建表达式时我被卡住了。方法调用因类型不兼容而崩溃。通常我知道放在那里什么,但 Any() 方法调用让我感到困惑。我已经尝试了所有我能想到的类型,但没有运气。任何帮助,将不胜感激。

这是我的实体类:

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

public IList<string> Contributors { get; set; }
}

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

var stories = new List<Story>();
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<T> Filter<T>(this IQueryable<T> query, IList<IFilterCriteria> 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<T>(mce);
}
}
return query;
}

public static Expression ToExpression<T>(this IList<IFilterCriteria> filterCriterias, IQueryable<T> 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<string, MemberExpression>(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<Story>();
var filters = new List<FilterCriteria>();
filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Author", FilterOperator = FilterOperator.Contains });

Expression<Func<string, bool>> func = t => t.Contains("Test");

filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Contributors", FilterOperator = FilterOperator.Contains, Expression = func });

stories.Filter(filters, LogicalOperator.Or).ToList();

但是在运行这段代码之后,我得到了这个我无法解决的错误

No generic method 'Any' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: No generic method 'Any' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.

Source Error:

Line 184: { Line 185:
var overload = typeof(Queryable).GetMethods().Single(mi => mi.Name == "Any" && mi.GetParameters().Count() == 2); Line 186:
Expression.Call(typeof(Queryable), "Any", new[] { typeof(string) }, propertyExpression, or); Line 187:
valueExpression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(string)}, propertyExpression, or, Expression.Constant("Test",

最佳答案

您不要在代码中的任何地方调用 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 ' 类型 'WpfApplication2.Story' 从范围 '' 引用,但未定义 错误。

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

关于c# - 子集合 List<string>.Any 的表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19748478/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com