C# 如何将viewmodel转换为表达式<;Func<;T、 布尔>>;?
背负着一个 我需要从ViewModel生成一个表达式,作为C# 如何将viewmodel转换为表达式<;Func<;T、 布尔>>;?,c#,ienumerable,expression-trees,iqueryable,func,C#,Ienumerable,Expression Trees,Iqueryable,Func,背负着一个 我需要从ViewModel生成一个表达式,作为IQueryable.Where的搜索谓词传递。我需要能够根据用户提供的内容包括/排除查询参数。例如: public class StoresFilter { public int[] Ids { get; set; } [StringLength(150)] public string Name { get; set; } [StringLength(5)] public string Abb
IQueryable.Where
的搜索谓词传递。我需要能够根据用户提供的内容包括/排除查询参数。例如:
public class StoresFilter
{
public int[] Ids { get; set; }
[StringLength(150)]
public string Name { get; set; }
[StringLength(5)]
public string Abbreviation { get; set; }
[Display(Name = "Show all")]
public bool ShowAll { get; set; } = true;
public Expression<Func<Store, bool>> ToExpression()
{
List<Expression<Func<Store, bool>>> expressions = new List<Expression<Func<Store, bool>>>();
if (Ids != null && Ids.Length > 0)
{
expressions.Add(x => Ids.Contains(x.Id));
}
if (Name.HasValue())
{
expressions.Add(x => x.Name.Contains(Name));
}
if (Abbreviation.HasValue())
{
expressions.Add(x => x.Abbreviation.Contains(Abbreviation));
}
if (!ShowAll)
{
expressions.Add(x => x.Enabled == true);
}
if (expressions.Count == 0)
{
return x => true;
}
// how to combine list of expressions into composite expression???
return compositeExpression;
}
}
公共类存储过滤器
{
公共int[]Ids{get;set;}
[长度(150)]
公共字符串名称{get;set;}
[第(5)款]
公共字符串缩写{get;set;}
[显示(Name=“全部显示”)]
公共bool ShowAll{get;set;}=true;
公共表达式ToExpression()
{
列表表达式=新列表();
如果(Ids!=null&&Ids.Length>0)
{
Add(x=>Ids.Contains(x.Id));
}
if(Name.HasValue())
{
Add(x=>x.Name.Contains(Name));
}
if(缩写为.HasValue())
{
expressions.Add(x=>x.缩写.Contains(缩写));
}
如果(!ShowAll)
{
Add(x=>x.Enabled==true);
}
if(expressions.Count==0)
{
返回x=>true;
}
//如何将表达式列表组合成复合表达式???
返回复合表达式;
}
}
有没有一种简单的方法可以从表达式列表构建复合表达式?或者我是否需要使用参数表达式
,表达式.以及,表达式访问者
等手动构建表达式的过程?void Main()
void Main()
{
var store = new Store
{
Id = 1,
Abbreviation = "ABC",
Enabled = true,
Name = "DEF"
};
var filter = new Filter<Store>
{
Ids = new HashSet<int>(new [] {1,2,3,4}),
Abbreviation = "GFABC",
Enabled = true,
Name = "SDEFGH",
ShowAll = false
}
var expression = filter.ToExpression(store);
var parameterType = Expression.Parameter(typeof(Store), "obj");
// Generate Func from the Expression Tree
Func<Store,bool> func = Expression.Lambda<Func<Store,bool>>(expression,parameterType).Compile();
}
public class Store
{
public int Id {get; set;}
public string Name {get; set;}
public string Abbreviation { get; set; }
public bool Enabled { get; set; }
}
public class Filter<T> where T : Store
{
public HashSet<int> Ids { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
public bool Enabled {get; set;}
public bool ShowAll { get; set; } = true;
public Expression ToExpression(T data)
{
var parameterType = Expression.Parameter(typeof(T), "obj");
var expressionList = new List<Expression>();
if (Ids != null && Ids.Count > 0)
{
MemberExpression idExpressionColumn = Expression.Property(parameterType, "Id");
ConstantExpression idConstantExpression = Expression.Constant(data.Id, typeof(int));
MethodInfo filtersMethodInfo = typeof(HashsetExtensions).GetMethod("Contains", new[] { typeof(HashSet<int>), typeof(int) });
var methodCallExpression = Expression.Call(null, filtersMethodInfo, idExpressionColumn, idConstantExpression);
expressionList.Add(methodCallExpression);
}
if (!string.IsNullOrEmpty(Name))
{
MemberExpression idExpressionColumn = Expression.Property(parameterType, "Name");
ConstantExpression idConstantExpression = Expression.Constant(data.Name, typeof(string));
MethodInfo filtersMethodInfo = typeof(StringExtensions).GetMethod("Contains", new[] { typeof(string), typeof(string) });
var methodCallExpression = Expression.Call(null, filtersMethodInfo, idExpressionColumn, idConstantExpression);
expressionList.Add(methodCallExpression);
}
if (!string.IsNullOrEmpty(Abbreviation))
{
MemberExpression idExpressionColumn = Expression.Property(parameterType, "Abbreviation");
ConstantExpression idConstantExpression = Expression.Constant(data.Abbreviation, typeof(string));
MethodInfo filtersMethodInfo = typeof(StringExtensions).GetMethod("Contains", new[] { typeof(string), typeof(string) });
var methodCallExpression = Expression.Call(null, filtersMethodInfo, idExpressionColumn, idConstantExpression);
expressionList.Add(methodCallExpression);
}
if (!ShowAll)
{
MemberExpression idExpressionColumn = Expression.Property(parameterType, "Enabled");
var binaryExpression = Expression.Equal(idExpressionColumn, Expression.Constant(true, typeof(bool)));
expressionList.Add(binaryExpression);
}
if (expressionList.Count == 0)
{
expressionList.Add(BinaryExpression.Constant(true));
}
// Aggregate List<Expression> data into single Expression
var returnExpression = expressionList.Skip(1).Aggregate(expressionList.First(), (expr1,expr2) => Expression.And(expr1,expr2));
return returnExpression;
// Generate Func<T,bool> - Expression.Lambda<Func<T,bool>>(returnExpression,parameterType).Compile();
}
}
public static class StringExtensions
{
public static bool Contains(this string source, string subString)
{
return source?.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
}
}
public static class HashsetExtensions
{
public static bool Contains(this HashSet<string> source, string subString)
{
return source.Contains(subString,StringComparer.OrdinalIgnoreCase);
}
}
{
var存储=新存储
{
Id=1,
缩写词=“ABC”,
启用=真,
Name=“DEF”
};
var过滤器=新过滤器
{
Ids=新哈希集(新[]{1,2,3,4}),
缩写词=“GFABC”,
启用=真,
Name=“SDEFGH”,
ShowAll=false
}
var expression=filter.ToExpression(存储);
var parameterType=表达式.参数(typeof(Store),“obj”);
//从表达式树生成Func
Func Func=Expression.Lambda(表达式,参数类型).Compile();
}
公共类商店
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共字符串缩写{get;set;}
已启用公共bool的{get;set;}
}
公共类筛选器,其中T:Store
{
公共哈希集ID{get;set;}
公共字符串名称{get;set;}
公共字符串缩写{get;set;}
已启用公共bool的{get;set;}
公共bool ShowAll{get;set;}=true;
公共表达式到表达式(T数据)
{
var parameterType=表达式参数(typeof(T),“obj”);
var expressionList=新列表();
如果(Ids!=null&&Ids.Count>0)
{
MemberExpression idExpressionColumn=Expression.Property(参数类型,“Id”);
ConstantExpression idConstantExpression=Expression.Constant(data.Id,typeof(int));
MethodInfo filtersMethodInfo=typeof(HashsetExtensions).GetMethod(“包含”,新[]{typeof(HashSet),typeof(int)});
var methodCallExpression=Expression.Call(null,filtersMethodInfo,idExpressionColumn,idConstantExpression);
Add(methodCallExpression);
}
如果(!string.IsNullOrEmpty(名称))
{
MemberExpression idExpressionColumn=Expression.Property(参数类型,“名称”);
ConstantExpression idConstantExpression=Expression.Constant(data.Name,typeof(string));
MethodInfo filtersMethodInfo=typeof(StringExtensions).GetMethod(“包含”,新[]{typeof(string),typeof(string)});
var methodCallExpression=Expression.Call(null,filtersMethodInfo,idExpressionColumn,idConstantExpression);
Add(methodCallExpression);
}
如果(!string.IsNullOrEmpty(缩写))
{
MemberExpression idExpressionColumn=Expression.Property(参数类型,“缩写”);
ConstantExpression idConstantExpression=表达式.Constant(data.缩写,typeof(string));
MethodInfo filtersMethodInfo=typeof(StringExtensions).GetMethod(“包含”,新[]{typeof(string),typeof(string)});
var methodCallExpression=Expression.Call(null,filtersMethodInfo,idExpressionColumn,idConstantExpression);
Add(methodCallExpression);
}
如果(!ShowAll)
{
MemberExpression idExpressionColumn=Expression.Property(参数类型,“Enabled”);
var binaryExpression=Expression.Equal(idExpressionColumn,Expression.Constant(true,typeof(bool));
expressionList.Add(二进制表达式);
}
if(expressionList.Count==0)
{
Add(BinaryExpression.Constant(true));
}
//将列表数据聚合到单个表达式中
var returnExpression=expressionList.Skip(1).Aggregate(expressionList.First(),(expr1,expr2)=>Expression.And(expr1,expr2));
返回表达式;
//生成Func-Expression.Lambda(返回表达式,参数类型).Compile();
}
}
公共静态类扩展
{
公共静态bool包含(此字符串源、字符串子字符串)
{
返回源?.IndexOf(子字符串,StringComparison.OrdinalIgnoreCase)>=0;
}
}
公共静态类HashsetExtensions
{
公共静态bool包含(此哈希集源、字符串子字符串)
{
返回source.Contains(子字符串、StringComparer.OrdinalIgnoreCase);
}
}
它是如何工作的
- 只有在简单的相等情况下,才可以使用
BinaryExpression
像Expression.Equal
,Expression.GreaterThan
,这是为“ShowAll”这样的属性显示的
- 对于其他情况,如
string/Array/List
Contains,您需要扩展方法,它可以采用两种类型并提供结果。环保总局
public IQueryable<Store> ApplyFilter(IQueryable<Store> source)
{
if (Ids != null && Ids.Length > 0)
source = source.Where(x => Ids.Contains(x.Id));
if (Name.HasValue())
source = source.Where(x => x.Name.Contains(Name));
if (Abbreviation.HasValue())
source = source.Where(x => x.Abbreviation.Contains(Abbreviation));
if (!ShowAll)
source = source.Where(x => x.Enabled == true);
//or return source.Expression as you wanted
return source;
}
var filter = new StoresFilter { Name = "Market" };
var filteredStores = filter.ApplyFilter(context.Stores).ToList();