c# - Extract all conditions from Expression by Type -
given expression<func<tentity, bool>>
along lines of
entity => entity.subentity.any( subentity => ( (subentity.someproperty == false) andalso subentity.subsubentity.fooproperty.startswith( value(someclass+<>c__displayclass0).comparisonproperty ) andalso subentity.subsubentity.barproperty == "bar" andalso subentity.subsubentity.subsubsubentity.any( subsubsubentity => (x.subsubsubsubentity.bazproperty == "whatever") ) ) )
i trying extract list property conditions type, i.e.
tentity : [ /* no conditions immediate members of tentity */ ] tsubentity : [ { someproperty == false } ] tsubsubentity : [ { fooproperty.startswith(/* ... */) }, { barproperty == "bar" } ], tsubsubsubentity : [ /* no conditions immediate members of tsubsubsubentity */ ], tsubsubsubsubentity : [ { bazproperty == "whatever" } ]
so far, have created expressionvisitor
, identified visitbinary
method 1 want plug in order obtain information.
i still @ loss about
- how determine whether
binaryexpression
looking @ represents terminal statement (in sense there no more nested expressions need at) - how determine entity type
binaryexpression
concerned with - whether need override of other
expressionvisitor
methods cover cases have not considered yet.
not sure use case, here starting point
class testvisitor : expressionvisitor { public dictionary<type, list<tuple<memberexpression, expression>>> result = new dictionary<type, list<tuple<memberexpression, expression>>>(); stack<expression> stack = new stack<expression>(); public override expression visit(expression node) { stack.push(node); base.visit(node); stack.pop(); return node; } protected override expression visitmember(memberexpression node) { if (node.expression.nodetype != expressiontype.constant && (node.type == typeof(string) || !typeof(ienumerable).isassignablefrom(node.type))) { var expression = stack.skip(1).firstordefault(); if (expression != null && expression.type == typeof(bool)) { list<tuple<memberexpression, expression>> resultlist; if (!result.trygetvalue(node.expression.type, out resultlist)) result.add(node.expression.type, resultlist = new list<tuple<memberexpression, expression>>()); resultlist.add(tuple.create(node, expression)); } } return base.visitmember(node); } }
the idea simple. override visit
method maintain stack of processing expressions. main processing inside visitmember
override, called each property/field accessor. node.expression.nodetype != expressiontype.constant
used eliminate closure members, while second condition eliminates collection properties. finally, potential condition expression extracted stack.
the result including both memberexpression
, expression
used. memberexpression.expression.type
entity type, memberexpression.member
property/field of type.
sample test:
class entity { public icollection<subentity> subentity { get; set; } } class subentity { public bool someproperty { get; set; } public subsubentity subsubentity { get; set; } } class subsubentity { public string fooproperty { get; set; } public string barproperty { get; set; } public icollection<subsubsubentity> subsubsubentity { get; set; } } class subsubsubentity { public subsubsubsubentity subsubsubsubentity { get; set; } } class subsubsubsubentity { public string bazproperty { get; set; } } class program { static void main(string[] args) { string comparisonproperty = "ivan"; expression<func<entity, bool>> e = entity => entity.subentity.any(subentity => subentity.someproperty == false && subentity.subsubentity.fooproperty.startswith(comparisonproperty) && subentity.subsubentity.barproperty == "bar" && subentity.subsubentity.subsubsubentity.any(subsubsubentity => subsubsubentity.subsubsubsubentity.bazproperty == "whatever") ); var v = new testvisitor(); v.visit(e); var result = v.result; } }
Comments
Post a Comment