我想在JSON对象上应用过滤条件
所以,我创建了一个表达式树来访问json节点,然后在其上应用转换/解析和 BinaryOperation
。
var stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Tags': ['Developer', 'Scrum Master'], 'Age': 42, }");
var leftExpressionTree = GetLeftExpressionTree("Name", stuff)
var binaryExpression = DoExpression(leftExpressionTree, "Jon Smith", ExpressionType.Equal)
//Complie and execute expression
public static Expression DoExpression(Expression leftExpression, string rightOperandStr, ExpressionType expressionType)
{
var leftExpressionConversionfromJtokenToString = Expression.Convert(leftExpression, typeof(string));
var rightExpression = Expression.Call(GetParseMethodForType(rightOperandStr), Expression.Constant(rightOperandStr));
var binaryExpression = Expression.MakeBinary(expressionType, leftExpressionConversionfromJtokenToString, rightExpression);
return binaryExpression;
}
没关系,"名称"是字符串类型,它起作用
但是,当我执行以下操作时,存在一个问题:
var leftExpressionTree = GetLeftExpressionTree("Tags")
var binaryExpression = DoExpression(leftExpressionTree, "Scrum Master", ExpressionType.Equal)
这不起作用,因为标签是JArray
。
当array
为时的预期行为时,必须将条件应用于所有数组项目,并且任何一个是正确的,则过滤器将通过
因此,必须为数组中的每个项目执行DoExpression
中编写的任何代码。
我该怎么做?请注意,我为简单性简化了DoExpression()
功能,实际功能中还有更多检查和条件。
这就是我这样做的方式。更改为Funcion返回结果而不是表达式
public static bool DoAction(JToken token, string rightOperand, ExpressionType type)
{
var str = (string) token;
var tokenExpr = Expression.Parameter(typeof(object));
var strExpr = Expression.Parameter(typeof(object));
var expr = Expression.MakeBinary(type, tokenExpr, strExpr);
var compiledExpr = Expression.Lambda<Func<object, object, bool>>(expr, tokenExpr, strExpr).Compile();
return compiledExpr(str, rightOperand);
}
一个函数,称枚举对象(jarray)上的"任何"
public static Expression GetArrayExpression(Expression leftExpression)
{
Type predType = typeof(Func<,>).MakeGenericType(typeof(JToken), typeof(bool));
MethodInfo anyMethod = (MethodInfo)GetGenericMethod(typeof(Enumerable), "Any", new[] { typeof(JToken) }, new[] { typeof(JArray), predType }, BindingFlags.Static);
MethodInfo miDoAction = typeof(Program).GetMethod("DoAction", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
ParameterExpression p = Expression.Parameter(typeof(JToken), "item");
var callExpr1 = Expression.Lambda<Func<JToken, bool>>(Expression.Call(miDoAction, p, Expression.Constant("SearchForThis"), Expression.Constant(ExpressionType.Equal)), p);
var callExpr = Expression.Call(anyMethod, leftExpression, callExpr1);
return callExpr;
}
如果是对象,则调用该函数的函数
public static Expression GetObjectExpression(Expression leftExpression)
{
MethodInfo miDoAction = typeof(Program).GetMethod("DoAction", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
var callExpr = Expression.Call(miDoAction, leftExpression, Expression.Constant("SearchForThis"), Expression.Constant(ExpressionType.Equal));
return callExpr;
}
那只是有条件调用的问题
Expression leftExpression;
var isTypeJarray = Expression.TypeIs(leftExpression, typeof(JArray));
return Expression.Condition(isTypeJarray, GetArrayExpression(leftExpression), GetObjectExpression(leftExpression));