C#学习教程:如何附加到表达式分享


如何附加到表达式

根据我昨天提出的问题 :

如果我必须附加到我现有的’where’表达式,我将如何追加?

Expression<Func> clientWhere = c => true; if (filterByClientFName) { clientWhere = c => c.ClientFName == searchForClientFName; } if (filterByClientLName) { clientWhere = c => c.ClientLName == searchForClientLName; } 

用户可以输入名字或姓氏或两者。 如果他们同时输入我想附加到表达式。 试着看看在我能做的地方是否有相应的附加物

 clientWhere.Append or clientWhere += add new expression 

或类似的东西

我相信你可以做到以下几点:

 Expression> 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 -land中(与IQueryable一起使用),您还可以执行以下操作:

 Expression> clientWhere = c => true; if (filterByClientFName) { Expression> newPred = c => c.ClientFName == searchForClientFName; clientWhere = Expression.Lambda>( Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters); } if (filterByClientLName) { Expression> newPred = c => c.ClientLName == searchForClientLName; clientWhere = Expression.Lambda>( Expression.AndAlso(clientWhere, newPred), clientWhere.Parameters); } 

通过定义此扩展方法,可以减少这种情况:

 public static Expression AndAlso(this Expression left, Expression right) { return Expression.Lambda(Expression.AndAlso(left, right), left.Parameters); } 

然后你可以使用这样的语法:

 Expression> clientWhere = c => true; if (filterByClientFName) { clientWhere = clientWhere.AndAlso(c => c.ClientFName == searchForClientFName); } if (filterByClientLName) { clientWhere = clientWhere.AndAlso(c => c.ClientLName == searchForClientLName); } 

这是一个复杂的场景。 您几乎在LINQ之上构建自己的查询引擎。 JaredPar的解决方案(它去了哪里?)如果你想要在所有标准之间进行逻辑AND,那就太棒了,但情况可能并非总是如此。

当我最近在我的一个项目中与此争吵时,我创建了两个列表:

 List> andCriteria; List> orCriteria; 

(在这种情况下,T是客户 ,为您服务)

我会使用谓词来填充列表,我希望它是真的。 例如,

 decimal salRequirement = 50000.00; andCriteria.Add(c => c.Salary > salRequirement); orCriteria.Add(c => c.IsMarried); 

然后,我将检查Where子句中列表中的所有条件。 例如:

 Expression> clientWhere = c => andCriteria.All(pred => pred(c) ) && orCriteria.Any(pred => pred(c) ); 

出于可读性的考虑,这也可以通过for循环完成。 在应用OR和AND子句时,请记住使用正确的操作顺序。

看看Predicate Builder ,我相信这可能适合你。

这不是你的问题的答案,但是,我正在寻找你的相同的事情,然后我找到了一个更好的答案我的问题。

您可以检索IQueryable,然后过滤您想要的内容,而不是构建动态表达式:

 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”语句,因为我担心这会在DataBase中生成多个查询,或者因为我必须检索所有记录然后过滤它们,但事实并非如此, 只有在调用.ToList()方法时,Linq动态才会生成一个查询。

在这里你可以看到我从中得到的原始问题。

或者要添加到Josh的东西(把它放在我的技巧包里):

 public static IQueryable ObjectFilter(this TSource SearchObject, List> andCriteria, List> orCriteria) where TSource : IQueryable { //Yeah :) Expression> ObjectWhere = O => andCriteria.All(pred => pred(O)) && orCriteria.Any(pred => pred(O)); return SearchObject.Where(ObjectWhere); } 

我试图实现这种东西。 花了一天时间才发现。 我的解决方案基于基于谓词数组的循环中的filter。 作为一个注释,它完全是Generic和基于Reflection,因为关于类和字段的唯一信息是String。 为简单起见,我直接调用Model类,但在项目中,您应该通过调用Model的控制器来进行调用。

所以这里我们去:Model部分,其中T是类中的Generic

  public class DALXmlRepository where T : class { public T GetItem(Array predicate) { IQueryable QueryList = null; QueryList = ObjectList.AsQueryable().Where((Expression>)predicate.GetValue(0)); for (int i = 1; i < predicate.GetLength(0); i++) { QueryList = QueryList.Where((Expression>)predicate.GetValue(i)); } if (QueryList.FirstOrDefault() == null) throw new InvalidOperationException(this.GetType().GetGenericArguments().First().Name + " not found."); return QueryList.FirstOrDefault(); } } 

现在LambdaExpression构建器,它是一个基础的(使用String类型或其他东西),你可以用更多的function来改进它:

  private static Expression BuildLambdaExpression(Type GenericArgument, string FieldName, string FieldValue) { LambdaExpression lambda = null; Expression Criteria = null; Random r = new Random(); ParameterExpression predParam = Expression.Parameter(GenericArgument, r.Next().ToString()); if (GenericArgument.GetProperty(FieldName).PropertyType == typeof(string)) { Expression left = Expression.PropertyOrField(predParam, FieldName); Expression LefttoUpper = Expression.Call(left, "ToUpper", null, null); //Type du champ recherché Type propType = GenericArgument.GetProperty(FieldName).PropertyType; Expression right = Expression.Constant(FieldValue, propType); Expression RighttoUpper = Expression.Call(right, "ToUpper", null, null); Criteria = Expression.Equal(LefttoUpper, RighttoUpper); } else { Expression left = Expression.PropertyOrField(predParam, FieldName); Type propType = GenericArgument.GetProperty(FieldName).PropertyType; Expression right = Expression.Constant(Convert.ChangeType(FieldValue, propType), propType); Criteria = Expression.Equal(left, right); } lambda = Expression.Lambda(Criteria, predParam); return lambda; } 

现在调用函数:

  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 XMLInstance = new DALXmlRepository(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> 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 }); } 

参数是:字符串实体:实体类名称。 XMLContext:它是存储库的工作单元,我用来初始化Model类的参数Hashtable FieldsNameToGet:我想要获取的字段列表的索引/值Hashtable FieldFilter:具有FieldName / Content的键/值制作Lambda表达式

祝好运。

上述就是C#学习教程:如何附加到表达式分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—猴子技术宅(www.ssfiction.com)

本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ssfiction.com/ckf/959908.html

发表评论

邮箱地址不会被公开。 必填项已用*标注