Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将viewmodel转换为表达式<;Func<;T、 布尔>>;?_C#_Ienumerable_Expression Trees_Iqueryable_Func - Fatal编程技术网

C# 如何将viewmodel转换为表达式<;Func<;T、 布尔>>;?

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

背负着一个

我需要从ViewModel生成一个表达式,作为
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();