C# 如何附加到表达式

C# 如何附加到表达式,c#,.net,linq,C#,.net,Linq,基于: 如果必须附加到现有的“where”表达式,我将如何附加 Expression<Func<Client, bool>> clientWhere = c => true; if (filterByClientFName) { clientWhere = c => c.ClientFName == searchForClientFName; } if (filterByClientLName) { clientWhere

基于:

如果必须附加到现有的“where”表达式,我将如何附加

Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    clientWhere = c => c.ClientFName == searchForClientFName;
}

 if (filterByClientLName)
    {
        clientWhere = c => c.ClientLName == searchForClientLName;
    }

或者类似的事情这是一个复杂的场景。您几乎正在LINQ之上构建自己的查询引擎。如果您希望在所有标准之间使用逻辑AND,那么JaredPar的解决方案(它去了哪里?)

当我最近在我的一个项目中讨论这个问题时,我创建了两个列表:

List<Predicate<T>> andCriteria;
List<Predicate<T>> orCriteria;
然后,我将对照Where子句中列表中的所有条件进行检查。例如:

Expression<Func<Client, bool>> clientWhere =
    c => andCriteria.All(pred => pred(c) ) && orCriteria.Any(pred => pred(c) );
表达式clientWhere=
c=>andCriteria.All(pred=>pred(c))&或criteria.Any(pred=>pred(c));

为了可读性,这也可以通过for循环来实现。在应用OR和and子句时,请记住使用正确的操作顺序。

我相信您可以执行以下操作:

Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    var prefix = clientWhere.Compile();
    clientWhere = c => prefix(c) && c.ClientFName == searchForClientFName;
}
if (filterByClientLName)
{
    var prefix = clientWhere.Compile();
    clientWhere = c => prefix(c) && c.ClientLName == searchForClientLName;
}
Expression<Func<Client, bool>> clientWhere = c => true;

if (filterByClientFName)
{
    Expression<Func<Client, bool>> newPred = 
        c => c.ClientFName == searchForClientFName;
    clientWhere = Expression.Lambda<Func<Freight, bool>>(
        Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters);
}
if (filterByClientLName)
{
    Expression<Func<Client, bool>> newPred = 
        c => c.ClientLName == searchForClientLName;
    clientWhere = Expression.Lambda<Func<Freight, bool>>(
        Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters);
}
通过定义此扩展方法,可以减少详细信息:

public static Expression<TDelegate> AndAlso<TDelegate>(this Expression<TDelegate> left, Expression<TDelegate> right)
{
    return Expression.Lambda<TDelegate>(Expression.AndAlso(left, right), left.Parameters);
}
公共静态表达式AndAlso(此表达式左,表达式右)
{
返回表达式.Lambda(表达式.AndAlso(左,右),左.参数);
}
然后可以使用如下语法:

Expression<Func<Client, bool>> clientWhere = c => true;
if (filterByClientFName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientFName == searchForClientFName);
}
if (filterByClientLName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientLName == searchForClientLName);
}
var customers = CustomerRepository.AllEntities();

if (!forename.IsNullOrEmpty())
    customers = customers.Where(p => p.Forename == forename);
if (!familyname.IsNullOrEmpty())
    customers = customers.Where(p => p.FamilyNames.Any(n => n.Name==familyname));
if (dob.HasValue)
    customers = customers.Where(p => p.DOB == dob);
Expression clientWhere=c=>true;
if(过滤器周期fName)
{
clientWhere=clientWhere.AndAlso(c=>c.ClientFName==searchForClientFName);
}
if(过滤器周期名称)
{
clientWhere=clientWhere.AndAlso(c=>c.ClientLName==searchForClientLName);
}

看一看,我相信这可能对你有用。

或者给Josh添加一些东西(放在我的技巧袋中):

公共静态IQueryable对象过滤器(此TSource SearchObject,List and Criteria,List or Criteria),其中TSource:IQueryable
{
//是的:)
表达式ObjectWhere=O=>andCriteria.All(pred=>pred(O))&&orCriteria.Any(pred=>pred(O));
返回SearchObject.Where(ObjectWhere);
}

这不完全是你问题的答案,但是,我一直在寻找与你相同的东西,然后我找到了一个更好的答案来回答我的问题

您可以检索IQueryable,而不是构建动态表达式 然后按如下方式筛选所需内容:

Expression<Func<Client, bool>> clientWhere = c => true;
if (filterByClientFName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientFName == searchForClientFName);
}
if (filterByClientLName)
{
    clientWhere = clientWhere.AndAlso(c => c.ClientLName == searchForClientLName);
}
var customers = CustomerRepository.AllEntities();

if (!forename.IsNullOrEmpty())
    customers = customers.Where(p => p.Forename == forename);
if (!familyname.IsNullOrEmpty())
    customers = customers.Where(p => p.FamilyNames.Any(n => n.Name==familyname));
if (dob.HasValue)
    customers = customers.Where(p => p.DOB == dob);
注意:我担心会执行多个“.Where”语句,因为我担心这会在数据库中生成多个查询,或者因为我必须检索所有记录,然后过滤它们,但这不是真的, Linq dynamic仅在调用.ToList()方法时生成一个查询。


您可以看到我从中获取示例的原始问题。

我尝试实现这种东西。我花了一天时间才弄清楚。 我的解决方案是基于谓词数组的循环中的过滤器。 值得注意的是,它是完全通用的、基于反射的,因为关于类和字段的唯一信息是字符串。 为了简单起见,我直接调用Model类,但在项目中,您应该由调用模型的控制器来执行

现在我们开始: 模型部分,其中T是类中的泛型

    public class DALXmlRepository<T> where T : class
    {
    public T GetItem(Array predicate)
    {
        IQueryable<T> QueryList = null;

        QueryList = ObjectList.AsQueryable<T>().Where((Expression<Func<T, bool>>)predicate.GetValue(0));
        for (int i = 1; i < predicate.GetLength(0); i++)
        {
            QueryList = QueryList.Where((Expression<Func<T, bool>>)predicate.GetValue(i));
        }

        if (QueryList.FirstOrDefault() == null)
            throw new InvalidOperationException(this.GetType().GetGenericArguments().First().Name + " not found.");
        return QueryList.FirstOrDefault();
    }
    }
现在调用函数:

    public static Hashtable GetItemWithFilter(string Entity, XMLContext contextXML, Hashtable FieldsNameToGet, Hashtable FieldFilter)
    {
        //Get the type
        Type type = Type.GetType("JP.Model.BO." + Entity + ", JPModel");
        Type CtrlCommonType = typeof(CtrlCommon<>).MakeGenericType( type );
        //Making an instance DALXmlRepository<xxx> XMLInstance = new DALXmlRepository<xxx>(contextXML);
        ConstructorInfo ci = CtrlCommonType.GetConstructor(new Type[] { typeof(XMLContext), typeof(String) });
        IControleur DalInstance = (IControleur)ci.Invoke(new object[] { contextXML, null });

        //Building the string type Expression<func<T,bool>> to init the array
        Type FuncType = typeof(Func<,>).MakeGenericType( type ,typeof(bool));
        Type ExpressType = typeof(Expression<>).MakeGenericType(FuncType);
        Array lambda = Array.CreateInstance(ExpressType,FieldFilter.Count);

        MethodInfo method = DalInstance.GetType().GetMethod("GetItem", new Type[] { lambda.GetType() });

        if (method == null)
            throw new InvalidOperationException("GetItem(Array) doesn't exist for " + DalInstance.GetType().GetGenericArguments().First().Name);

        int j = 0;
        IDictionaryEnumerator criterias = FieldFilter.GetEnumerator();
        criterias.Reset();
        while (criterias.MoveNext())
        {
            if (!String.IsNullOrEmpty(criterias.Key.ToString()))
            {
                lambda.SetValue(BuildLambdaExpression(type, criterias.Key.ToString(), criterias.Value.ToString()),j);
            }
            else
            {
                throw new JPException(JPException.MessageKey.CONTROLER_PARAMFIELD_EMPTY, "GetItemWithFilter", criterias.Key.ToString());
            }
            j++;
        }

        Object item = method.Invoke(DalInstance, new object[] { lambda });
        }
public静态哈希表GetItemWithFilter(字符串实体、XMLContext contextXML、哈希表字段snametoget、哈希表字段筛选器)
{
//获取类型
Type Type=Type.GetType(“JP.Model.BO.+Entity+”,JPModel”);
类型CtrlCommonType=typeof(CtrlCommon)。MakeGenericType(类型);
//创建实例DALXmlRepository XMLInstance=新的DALXmlRepository(contextXML);
ConstructorInfo ci=CtrlCommonType.GetConstructor(新类型[]{typeof(XMLContext),typeof(String)});
IControleur dainstance=(IControleur)ci.Invoke(新对象[]{contextXML,null});
//构建字符串类型表达式以初始化数组
Type FuncType=typeof(Func).MakeGenericType(Type,typeof(bool));
类型ExpressType=typeof(表达式)。MakeGenericType(FuncType);
数组lambda=Array.CreateInstance(ExpressType,FieldFilter.Count);
MethodInfo method=daInstance.GetType().GetMethod(“GetItem”,新类型[]{lambda.GetType()});
if(方法==null)
抛出新的InvalidOperationException(“GetItem(数组)不存在于“+DaInstance.GetType().GetGenericArguments().First().Name”);
int j=0;
IDictionaryEnumerator criterias=FieldFilter.GetEnumerator();
Reset();
while(criterias.MoveNext())
{
如果(!String.IsNullOrEmpty(criterias.Key.ToString()))
{
SetValue(BuildLambdaExpression(类型,criterias.Key.ToString(),criterias.Value.ToString()),j);
}
其他的
{
抛出新的JPException(JPException.MessageKey.Controller_PARAMFIELD_EMPTY,“GetItemWithFilter”,criterias.Key.ToString());
}
j++;
}
objectitem=method.Invoke(daInstance,新对象[]{lambda});
}
理由是: 字符串实体:实体类名称。 XMLContext:它是存储库的工作单元,是我用来初始化模型类的参数 Hashtable FieldsNameToGet:我要返回的字段列表的索引/值 Hashtable FieldFilter:用于生成Lambda表达式的字段名/内容的键/值


祝你好运。

如果你遇到类似的问题,你可以在这个伟大的网站上找到所有可能的解决方案。 或者只需使用PredicateBuilder就可以了

var predicate = PredicateBuilder.True<Client>();

if (filterByClientFName)
{
    predicate = predicate.And(c => c.ClientFName == searchForClientFName);
}

if (filterByClientLName)
{
        predicate = predicate.And(c => c.ClientLName == searchForClientLName);
}

var result = context.Clients.Where(predicate).ToArray();
var predicate=PredicateBuilder.True();
if(过滤器周期fName)
{
谓词=谓词。和(c=>c.ClientFName==searchForClientFName);
}
if(过滤器周期名称)
{
谓词=谓词和(c=>c.ClientLName==searchForClientLName);
}
var result=context.Clients.Where(谓词).ToArray();
这是一些生成器实现

public static class PredicateBuilder
    {
        // Creates a predicate that evaluates to true.        
        public static Expression<Func<T, bool>> True<T>() { return param => true; }

        // Creates a predicate that evaluates to false.        
        public static Expression<Func<T, bool>> False<T>() { return param => false; }

        // Creates a predicate expression from the specified lambda expression.        
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }

        // Combines the first predicate with the second using the logical "and".        
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        // Combines the first predicate with the second using the logical "or".        
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        // Negates the predicate.        
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }

        // Combines the first expression with the second using the specified merge function.        
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        class ParameterRebinder : ExpressionVisitor
        {
            readonly Dictionary<ParameterExpression, ParameterExpression> map;

            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }
    }
公共静态类谓词生成器
{
//创建一个计算结果为true的谓词。
公共图书馆
var predicate = PredicateBuilder.True<Client>();

if (filterByClientFName)
{
    predicate = predicate.And(c => c.ClientFName == searchForClientFName);
}

if (filterByClientLName)
{
        predicate = predicate.And(c => c.ClientLName == searchForClientLName);
}

var result = context.Clients.Where(predicate).ToArray();
public static class PredicateBuilder
    {
        // Creates a predicate that evaluates to true.        
        public static Expression<Func<T, bool>> True<T>() { return param => true; }

        // Creates a predicate that evaluates to false.        
        public static Expression<Func<T, bool>> False<T>() { return param => false; }

        // Creates a predicate expression from the specified lambda expression.        
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }

        // Combines the first predicate with the second using the logical "and".        
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        // Combines the first predicate with the second using the logical "or".        
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        // Negates the predicate.        
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }

        // Combines the first expression with the second using the specified merge function.        
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        class ParameterRebinder : ExpressionVisitor
        {
            readonly Dictionary<ParameterExpression, ParameterExpression> map;

            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }
    }
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
    {
        return first.Compose(second, Expression.And);
    }