C# 如何创建更复杂的 .Any() 表达式
C# how create a more complex .Any() expression
我有这个过滤器数组,其中包含 属性 名称、值和 属性 类型。
基于 PropertyType,我构建了一个表达式,最后我得到的是一个表达式列表,然后我将其与 And 聚合。
return filter?
.Where(f => !string.IsNullOrEmpty(f.Value))?
.Select(f =>
{
var parameter = Expression.Parameter(typeof(T), "item");
var property = Expression.Property(parameter, PascalCase(f.PropertyName));
Expression expression = null;
if (f.Type == PropertyTypeEnum.String)
{
var toLowerMethod = typeof(string).GetMethod("ToLower", new Type[] { });
var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var value = Expression.Constant(f.Value.ToLower());
var loweredProperty = Expression.Call(property, toLowerMethod);
expression = Expression.Call(loweredProperty, startsWithMethod, value);
}
else
{
var value = Convert.ChangeType(f.Value, property.Type);
ConstantExpression constantExpression = Expression.Constant(value);
expression = Expression.Equal(property, constantExpression);
}
return Expression.Lambda<Func<T, bool>>(expression, parameter);
});
我放在 Linq 中。如果枚举类型是字符串,它看起来像这样
.Where(x => x.ToLower().StartsWith(someString)).
现在我可以选择 PropertyType 是 Array 并且我想要这个表达式
(x => x.Any(y => y.ToLower().StartsWith(someString)));
但是我究竟该如何构建这样的表达式呢?
设法让它工作。这是 case 语句中的代码
var innerProperty = Expression.PropertyOrField(parameter, PascalCase(f.PropertyName));
var innerParameter = Expression.Parameter(typeof(string), "y");
var toLowerMethod = typeof(string).GetMethod(nameof(string.ToLower), new Type[] { });
var startsWithMethod = typeof(string).GetMethod(nameof(string.StartsWith), new[] { typeof(string) });
var value = Expression.Constant(f.Value.ToLower());
var loweredProperty = Expression.Call(innerParameter, toLowerMethod);
var innerExp = Expression.Call(loweredProperty, startsWithMethod, value);
var predicate = Expression.Lambda<Func<string, bool>>(innerExp, innerParameter);
expression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(string) }, innerProperty, predicate);
我有这个过滤器数组,其中包含 属性 名称、值和 属性 类型。 基于 PropertyType,我构建了一个表达式,最后我得到的是一个表达式列表,然后我将其与 And 聚合。
return filter?
.Where(f => !string.IsNullOrEmpty(f.Value))?
.Select(f =>
{
var parameter = Expression.Parameter(typeof(T), "item");
var property = Expression.Property(parameter, PascalCase(f.PropertyName));
Expression expression = null;
if (f.Type == PropertyTypeEnum.String)
{
var toLowerMethod = typeof(string).GetMethod("ToLower", new Type[] { });
var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var value = Expression.Constant(f.Value.ToLower());
var loweredProperty = Expression.Call(property, toLowerMethod);
expression = Expression.Call(loweredProperty, startsWithMethod, value);
}
else
{
var value = Convert.ChangeType(f.Value, property.Type);
ConstantExpression constantExpression = Expression.Constant(value);
expression = Expression.Equal(property, constantExpression);
}
return Expression.Lambda<Func<T, bool>>(expression, parameter);
});
我放在 Linq 中。如果枚举类型是字符串,它看起来像这样
.Where(x => x.ToLower().StartsWith(someString)).
现在我可以选择 PropertyType 是 Array 并且我想要这个表达式
(x => x.Any(y => y.ToLower().StartsWith(someString)));
但是我究竟该如何构建这样的表达式呢?
设法让它工作。这是 case 语句中的代码
var innerProperty = Expression.PropertyOrField(parameter, PascalCase(f.PropertyName));
var innerParameter = Expression.Parameter(typeof(string), "y");
var toLowerMethod = typeof(string).GetMethod(nameof(string.ToLower), new Type[] { });
var startsWithMethod = typeof(string).GetMethod(nameof(string.StartsWith), new[] { typeof(string) });
var value = Expression.Constant(f.Value.ToLower());
var loweredProperty = Expression.Call(innerParameter, toLowerMethod);
var innerExp = Expression.Call(loweredProperty, startsWithMethod, value);
var predicate = Expression.Lambda<Func<string, bool>>(innerExp, innerParameter);
expression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(string) }, innerProperty, predicate);