рд╢реБрдн рджреЛрдкрд╣рд░
рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдХрд┐рд╕реА рдФрд░ рдХреЗ рдХреЛрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреЗрдЦрдиреЗ рдкрд░, рдореБрдЭреЗ IQueryable рдФрд░ рдПрдХреНрд╕рдкреЛрдЬрд╝рд░ рдкреЗрдбрд╝реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рд╕рдорд╕реНрдпрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрддрд╛ рдЪрд▓рд╛ред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд╕рдорд╛рдзрд╛рди рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ред
рдХрд╛рд░реНрдп рдПрдХ рдФрд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рдЕрдВрджрд░ рдХреБрдЫ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ
рдПрдл рд╣реИрдВ :
Expression<Func<int, int, int>> f = (a, b) => a + b;
рдФрд░ рд╣рдо рдЗрд╕
f рдХрд╛ рдЙрдкрдпреЛрдЧ рджреВрд╕рд░реА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рдЕрдВрджрд░ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЗрд╕ рддрд░рд╣:
Expression<Func<int, int, int, int>> g = (a, b, c) => f(a+b,b)*c;
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдкрд░рд┐рдгрд╛рдореА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ "рд╢реБрджреНрдз" рд╣реЛ, рдЕрд░реНрдерд╛рддреНред IQueryable рдХреЗ рдЕрдВрджрд░ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд (рд╕рдВрдХрд▓рд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмрд┐рдирд╛, рдЖрджрд┐)
рдпрджрд┐ рдЖрдк рдЗрди рджреЛ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ g рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рдЧрд▓рдд рд╣реИ:
'f' рдПрдХ 'рд╡реИрд░рд┐рдПрдмрд▓' рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ 'рдореЗрдердб' рдХреА рддрд░рд╣ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ , рдЬреЛ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ рдХрд┐ f рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╡реГрдХреНрд╖ рдХреА рдЬрдбрд╝ рд╣реИ, рдФрд░ рди рд╣реА рдпрджрд┐ рдХреЛрдИ рдлрд╝рдВрдХреНрд╢рди рдпрд╛ рдлрд╝рдВрдХреНрдЯрд░ рдирд╣реАрдВ рд╣реИред рдЖрдк рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
Expression<Func<int, int, int, int>> g = (a, b, c) => f.Compile()(a+b,b)*c;
рд▓реЗрдХрд┐рди рддрдм рд╣рдорд╛рд░реА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдЕрдВрддрддрдГ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:
(a, b, c) => (Invoke(value(ExpressionReducer.Program+<>c__DisplayClass0).f.Compile(), (a + b), b) * c)
рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рд╣рдорд╛рд░реЗ IQueryable рдЗрд╕реЗ рд╕рдордЭ рдирд╣реАрдВ рдкрд╛рдПрдВрдЧреЗред
рд╕рдмрд╕реЗ рд╕рд░рд▓ рдФрд░ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рдЪрд╛рд░ рдХреЗрд╡рд▓ рдЕрдкрдиреЗ рд╢рд░реАрд░ рдХреЗ рд▓рд┐рдП f рдХреЛ рд╕реНрдерд╛рдирд╛рдкрдиреНрди рдХрд░рдирд╛ рд╣реИ - рдореЛрдЯреЗ рддреМрд░ рдкрд░, g рдореЗрдВ рдкрдж f рдХрд╛ "рдПрдкреНрд▓рд┐рдХреЗрд╢рди" рдмрдирд╛рдПрдВ (рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ, рдореИрдВ рд▓реИрдореНрдмреНрдбрд╛ рд╡рд┐рд▓реБрдкреНрдд рд╣реЛрдиреЗ рдкрд░ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдордЬрдмреВрдд рдирд╣реАрдВ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореЗрд░реА рд░рд╛рдп рдореЗрдВ рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рдПрдХ рдЖрд╡реЗрджрди рд╣реЛрдЧрд╛)ред
рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ "рдЖрд╡реЗрджрди" рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЬреА рдЯреНрд░реА рдХреЗ рд▓рд┐рдП рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдЯреНрд░реА рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢рд░реАрд░ рдХреЗ рд╕рд╛рде рдЗрдирд╡реЛрдХ (рдХрдВрдкрд╛рдЗрд▓ ()) рдХреЙрд▓ рдХреЛ рдмрджрд▓реЗрдВ, рдФрд░ рдмреЙрдбреА рдореЗрдВ рдЕрдкрдиреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдЗрдирд╡реЙрдЗрд╕ рддрд░реНрдХреЛрдВ рдХреЗ рдорд╛рдиреЛрдВ рд╕реЗ рдмрджрд▓реЗрдВ, рдЕрд░реНрдерд╛рддреН: рд╕реЗ:
(a, b, c) => f.Compile()(a+b,b)*c
рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП
(a, b, c) => ((a+b)+b)*c
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдЗрдП рд╣рдо рднрд╛рд░реА рдЪрд╛рд▓рд╛рди (рд╕рдВрдХрд▓рди) рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдПрдВ рдФрд░ рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдХреА рд╡рд┐рд╕реНрддрд╛рд░ рд╡рд┐рдзрд┐ рд╕реЗ рдмрджрд▓реЗрдВ:
public static T Apply<T,T1,T2>(this Expression<Func<T1,T2,T>> expression, T1 t1, T2 t2) { return expression.Compile()(t1, t2); }
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рд╢рд░реАрд░ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИ - рдпрд╣ рд░реВрдкрд╛рдВрддрд░рдг рдХреЗ рджреМрд░рд╛рди рдХрднреА рдирд╣реАрдВ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдХрд┐рд╕реА рдХреЗ рд╕рд░рд▓реАрдХрд░рдг рдХреЗ рдмрд┐рдирд╛ рдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдкрд░ рдПрдХ рд╡реИрдз рдирд┐рдХрд╛рдп рд╣реЛрдирд╛ рдЙрдкрдпреЛрдЧреА рд╣реИред
рдЕрдм рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдкреЗрдбрд╝ рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣рд╛рдБ рдХрджрдо рдЙрдард╛рдП рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ:
- рдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВред
- рдкрд╣рд▓реЗ рддрд░реНрдХ рд╕реЗ рд▓рд╛рдЧреВ рд╕рдорд╛рд░реЛрд╣ рдХреЗ рд▓рд┐рдП рд▓рдВрдмреЛ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред
- рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢реЗрд╖ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рд▓реИрдореНрдмреНрдбрд╛ рдмреЙрдбреА рдореЗрдВ рддрд░реНрдХреЛрдВ рдХреЛ рдмрджрд▓реЗрдВред
- рдмрджрд▓реЗрдВред рдЫреЛрдЯреЗ рдкреЗрдбрд╝ рдХреЛ рд╢рд░реАрд░ f рдХреЗ рд╕рд╛рде рдмрджрд▓реЗрдВред
рдкрд╣рд▓рд╛ рдЖрдЗрдЯрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдЖрд╕рд╛рди рд╣реИ - рд╣рдо System.Linq.Expressions рдирд╛рдо рд╕реНрдерд╛рди рд╕реЗ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рд╡рд┐рдЬрд┐рдЯрд░ рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╡рд░реНрдЧ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рди рдХреЗрд╡рд▓ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдкреЗрдбрд╝ рдХреЗ рд╕рднреА рдиреЛрдбреНрд╕ рдкрд░ рдЬрд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдЗрд╕рдХреЗ рдХреБрдЫ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рднреА рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддрд╛ рд╣реИ (рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП
http://msdn.microsoft.com/en-us/library/bb546136/28v=vs.90%29.aspx рджреЗрдЦреЗрдВ ) рд╣рдо рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд▓рд╛рдЧреВ рд╡рд┐рдзрд┐ ExpressionReductor рд╡рд░реНрдЧ рдореЗрдВ рд╣реИ:
private class InvokerVisitor : ExpressionVisitor { protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.DeclaringType == typeof (ExpressionReductor) && node.Method.Name == "Apply") {
рджреВрд╕рд░рд╛ рдмрд┐рдВрджреБ рдХреБрдЫ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдкреЗрдбрд╝ рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, f рдСрдЯреЛ-рдЬреЗрдирд░реЗрдЯреЗрдб рдХреНрд▓рд╛рд╕ ExpressionReducer.Program + <> c__DisplayClass0 рдХрд╛ рдПрдХ рдХреНрд╖реЗрддреНрд░ рдмрди рдЧрдпрд╛ рд╣реИ - рдпрд╣ рд╣реИ рдХрд┐ C # рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдП рдЧрдП рд╕рднреА рдлрдВрдХреНрд╢рдВрд╕ рдпрд╛ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдпрд╛ рд╡рд┐рдзрд┐ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдЖрддрд╛ рд╣реИред рдЕрдиреНрдп рд╡рд┐рдХрд▓реНрдкреЛрдВ рдореЗрдВ рд╕реЗ, рдпрд╣ рдПрдХ рдирд╛рдорд┐рдд рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдХреНрд╖реЗрддреНрд░ рдпрд╛ рд╕рдВрдкрддреНрддрд┐ рдпрд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЙрд▓ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реИред
рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рдХреЗрд╡рд▓ рдкрд╣рд▓реЗ рдорд╛рдорд▓реЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ (рдмрд╛рдХреА рдХреЛ рд╕рдорд╛рди рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ): рдПрдл рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╡рд░реНрдЧ рдХрд╛ рдХреНрд╖реЗрддреНрд░ рд╣реИред
class FieldLambdaFinder : ExpressionVisitor { protected override Expression VisitMember(MemberExpression node) { var constantExpression = (ConstantExpression) node.Expression; var info = (FieldInfo) node.Member; var fieldValue = (Expression)info.GetValue(constantExpression.Value); return fieldValue; } public Expression Find(Expression expression) { return Visit(expression); } }
рддреАрд╕рд░рд╛ рдЖрдЗрдЯрдо рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ - рдЖрдЗрдП рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд▓рд┐рдЦреЗрдВ (рдкреИрд░рд╛рдореАрдЯрд░ f -> рдкреИрд░рд╛рдореАрдЯрд░ рд▓рд╛рдЧреВ рдХрд░реЗрдВ) рдФрд░ f рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рд╕рднреА ParameterExpression рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:
internal class Replacer : ExpressionVisitor { private Dictionary<ParameterExpression, Expression> _replacements; public Replacer(IEnumerable<ParameterExpression> what, IEnumerable<Expression> with) { _replacements = what.Zip(with, (param, expr) => new { param, expr }).ToDictionary(x => x.param, x => x.expr); } public Expression Replace(Expression body) { return Visit(body); } protected override Expression VisitParameter(ParameterExpression node) { Expression replacement; return _replacements.TryGetValue(node, out replacement) ? replacement : base.VisitParameter(node); } }
рдЕрдВрддрд┐рдо рдЖрдЗрдЯрдо рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдореЗрдВ рд╕рдм рдХреБрдЫ рджрд┐рдЦрд╛рдПрдЧрд╛:
private class InvokerVisitor : ExpressionVisitor { protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.DeclaringType == typeof (ExpressionReductor) && node.Method.Name == "Apply") { var lambda = GetLambda(node.Arguments[0]); return Replace(lambda, node.Arguments.Skip(1)); } return base.VisitMethodCall(node); } private Expression Replace(LambdaExpression lambda, IEnumerable<Expression> arguments) { var replacer = new Replacer(lambda.Parameters, arguments); return replacer.Replace(lambda.Body); } private LambdaExpression GetLambda(Expression expression) { var finder = new FieldLambdaFinder(); return (LambdaExpression) finder.Find(expression); } }
рдЦреБрдж рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреА рд╡рд┐рдзрд┐:
public static Expression<T> Simplify<T>(this Expression<T> expression) { var invoker = new InvokerVisitor(); return (Expression<T>) invoker.Visit(expression); }
рдПрдХ рдмрд╛рд░ рдореЗрдВ рд╕рдм рдХреБрдЫ
рдпрд╣рд╛рдБ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ ред
рдирддреАрдЬрддрди, рд╣рдореЗрдВ рд╡рд╣ рдорд┐рд▓рд╛ рдЬреЛ рд╣рдо рдЪрд╛рд╣рддреЗ рдереЗ:
Expression<Func<int, int, int>> f = (a, b) => a + b; Expression<Func<int, int, int, int>> g = (a, b, c) => f.Apply(a + b, b)*c; g = g.Simplify();
рд╢реЗрд╖ рд╕рдорд╕реНрдпрд╛рдПрдВ:
- рдЕрдиреНрдп рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдПрдл рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред
- рдпрджрд┐ рд▓рд╛рдЧреВ рдкреИрд░рд╛рдореАрдЯрд░ рдЕрдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рд╣реЛрддреЗ рд╣реИрдВ рдЬрд┐рдирдХреЗ рджреБрд╖реНрдкреНрд░рднрд╛рд╡ рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдЧрд▓рдд рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо IQueryable рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдЗрд╕реЗ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред
- рд╕рд░рд▓реАрдХреГрдд рдлрд╝рдВрдХреНрд╢рди рдЧрдгрдирд╛ рдХреЛ рдзреНрд╡рд╕реНрдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ: f.Apply (5, 5) рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ (5 + 5), рдФрд░ рдирд╣реАрдВ (10)ред
- рд╕рд░рд▓реАрдХреГрдд рдлрд╝рдВрдХреНрд╢рди рдкреБрдирд░рд╛рд╡рд░реНрддреА рдирд╣реАрдВ рд╣реИ, рдЕрд░реНрдерд╛рддреН, рдРрд╕реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдкрд░ - f.Apply (a, f.Apply (b, c)) - рдЗрд╕реЗ рдХрдИ рдмрд╛рд░ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред