linq - Currying Expressions in C# -
i trying build expression tree can feed linq2sql generate nice clean query. purpose build filter takes arbitrary set of words , and not (or or , not) together. because want vary fields search on preferably want compose list of expresssion<func<t, string, bool>>'s (where t entity operating on) calling variety of helper functions. receive array of words , loop though them , build expresssion<func<t, bool>> (negating expressions necessary) can feed .where statement.
i have been using linqkit predicatebuilder code deals single parameter expressions. however, has provided me groundwork own attempts. aiming this:
var e = (expression<func<entity, string, bool>>)((p, w) => p.somefield.tolower().contains(w)); var words = new []{"amanda", "bob"}; var expr = (expression<func<entity, bool>>)(p => false); // building or query foreach(var w in words) { var w1 = w; >>>>expr = expression.lambda<func<entity, bool>>(expression.orelse(expr.body, (expression<func<entity, bool>>)(p => e(p, w)))); } var filteredentities = table.where(expr); but since using expressions line marked >>>> illegal (cannot e(p, w) function). question how do partial application of single variable (the word) expressions containing functions multiple parameters?
okay, fiddled around in linqpad , figured out solution works me. this question got me there. pretty new building expression trees appreciate (and upvote) comments/answers improvements or criticism.
// set of expressions test against var expressions = new list<expression<func<entity, string, bool>>>(); expressions.add((p, w) => p.firstname.tolower().contains(w)); expressions.add((p, w) => p.lastname.tolower().contains(w)); expressions.add((p, w) => p.department != null && p.department.name.tolower().contains(w)); var words = new []{"amanda", "bob"}; var negs = new []{"smith"}; // exclude entries including these words var isandquery = true; // negate or query expression<func<entity, bool>> posexpr = p => isandquery; var entityparameter = expression.parameter(typeof(entity), null); // build nots var negexpr = (expression<func<entity, bool>>)(p => true); foreach(var w in negs) { var w1 = w; foreach(var e in expressions) { var andnot = expression.invoke(e, entityparameter, expression.constant(w1)); negexpr = expression.lambda<func<entity, bool>>(expression.andalso(negexpr.body, expression.not(andnot)), entityparameter); } } // build ands or ors foreach(var w in words) { var w1 = w; var orexpr = (expression<func<entity, bool>>)(p => false); foreach(var e in expressions) { var orelse = expression.invoke(e, entityparameter, expression.constant(w1)); orexpr = expression.lambda<func<entity, bool>>(expression.orelse(orexpr.body, orelse), entityparameter); } var orinvoked = expression.invoke(orexpr, posexpr.parameters.cast<expression>()); if(isandquery) posexpr = expression.lambda<func<entity, bool>>(expression.andalso(posexpr.body, orinvoked), entityparameter); else posexpr = expression.lambda<func<entity, bool>>(expression.orelse(posexpr.body, orinvoked), entityparameter); } var posinvoked = expression.invoke(posexpr, posexpr.parameters.cast<expression>()); var finalexpr = expression.lambda<func<entity, bool>>(expression.andalso(negexpr.body, posinvoked), entityparameter); var filteredentities = entities.where(finalexpr);
this example might you. guess best build expression without lambdas:
public class entity { public entity(string somefield) { somefield = somefield; } public string somefield { get; set; } } class program { static void main(string[] args) { var entities = new[] {new entity("foobar"), new entity("barbaz"), new entity("baz"), new entity("foo")}; entities.where(buildexpression("ar","az").compile()) .tolist() .foreach(e => console.writeline(e.somefield)); console.readline(); } public static expression<func<entity, bool>> buildexpression(params string[] words) { var parameter = expression.parameter(typeof (entity)); var matchs = words.select(word => { var property = expression.property(parameter, "somefield"); var tolower = expression.call(property, "tolower", new type[] {}); var contains = expression.call(tolower, "contains", new type[]{}, expression.constant(word)); return contains; }).oftype<expression>(); var body = matchs.aggregate(expression.or); return expression.lambda<func<entity, bool>>(body, new[] {parameter}); } } please let me know if should add more information answer.
Comments
Post a Comment