c# - How should I share filtering logic between multiple LINQ-where clauses? -
let a
class whith property hello
. filter collections of a
instances property in many places. i'd make somewhere static member of type expression<func<a, bool>>
denotes filtering predicate , use in places filtering. (this predicate transformed orm concrete db-specific expression.)
next. there exists class b
property of type a
. filter collection of b
instances same logic used in first case (by property hello
of class a
).
question. correct way implement , reduce code duplication?
my suggestion. add 3 things: 1) interface iwitha
property of type a
, 2) class witha<t>
implementing interface iwitha
, providing property of type t
, 3) static property of type expression<func<iwitha, bool>>
implementing filtering logic. demo code following.
public static void main() { var listofas = new list<a>().asqueryable(); var query0 = listofas .select(a => new witha<a> { = a, smth = a, }) .where(filter); var listofbs = new list<b>().asqueryable(); var query1 = listofbs .select(b => new witha<b> { = b.a, smth = b, }) .where(filter); } private class { public int hello { get; set; } } private class b { public a { get; set; } } private interface iwitha { a { get; set; } } private class witha<t> : iwitha { public a { get; set; } public t smth { get; set; } } private static readonly expression<func<iwitha, bool>> filter = => a.a.hello > 0;
the problem approach: 1) 1 must make select(x => new witha<x> { ... })
, 2) orm may not support this.
about answer. satisfied accepted answer (by ivan stoev). think best possible approach. helpful @ suggestion mihail stancescu (see in comments question). still not understand answer user853710; may useful also.
i create , use helper function converts original expression<a, bool>
expression<b, bool>
using system.linq.expressions
this
public static class expressionutils { public static expression<func<ttarget, bool>> convertto<tsource, ttarget>(this expression<func<tsource, bool>> source, expression<func<ttarget, tsource>> sourceselector) { var body = new parameterexpressionreplacer { source = source.parameters[0], target = sourceselector.body }.visit(source.body); var lambda = expression.lambda<func<ttarget, bool>>(body, sourceselector.parameters); return lambda; } class parameterexpressionreplacer : expressionvisitor { public parameterexpression source; public expression target; protected override expression visitparameter(parameterexpression node) { return node == source ? target : base.visitparameter(node); } } }
sample usage
expression<func<a, bool>> filtera = item => item.hello == 2; // original logic var filterb = filtera.convertto((b b) => b.a);
this approach doesn't require changes entity model. of course can cache filters in static properties of respective classes if wish, principle still write logic in 1 place , use convert in other places.
Comments
Post a Comment