Line data Source code
1 : using System;
2 : using System.Collections.Generic;
3 : using System.Linq;
4 : using System.Linq.Expressions;
5 : using System.Reflection;
6 :
7 : namespace Cqrs.Sql.DataStores
8 : {
9 : public abstract class ExpressionTreeConverter<TA, TB> : ExpressionVisitor, IExpressionTreeConverter
10 0 : {
11 : private readonly Dictionary<ParameterExpression, ParameterExpression> _parameters = new Dictionary<ParameterExpression, ParameterExpression>();
12 :
13 : private readonly Dictionary<MemberInfo, LambdaExpression> _mappings;
14 :
15 0 : protected ExpressionTreeConverter(Dictionary<MemberInfo, LambdaExpression> mappings)
16 : {
17 : _mappings = mappings;
18 : }
19 :
20 0 : protected ExpressionTreeConverter()
21 : {
22 : _mappings = GetMappings();
23 : }
24 :
25 0 : public abstract Dictionary<MemberInfo, LambdaExpression> GetMappings();
26 :
27 0 : protected override Expression VisitParameter(ParameterExpression node)
28 : {
29 : if (node.Type == typeof(TA))
30 : {
31 : ParameterExpression parameter;
32 : if (!_parameters.TryGetValue(node, out parameter))
33 : {
34 : _parameters.Add(node, parameter = Expression.Parameter(typeof(TB), node.Name));
35 : }
36 : return parameter;
37 : }
38 : return node;
39 : }
40 :
41 0 : protected override Expression VisitMember(MemberExpression node)
42 : {
43 : if (node.Expression == null || node.Expression.Type != typeof(TA))
44 : return base.VisitMember(node);
45 :
46 : Expression expression = Visit(node.Expression);
47 : if (expression.Type != typeof(TB))
48 : throw new Exception("Whoops");
49 :
50 : LambdaExpression lambdaExpression;
51 : if (_mappings.TryGetValue(node.Member, out lambdaExpression))
52 : return new SimpleExpressionReplacer(lambdaExpression.Parameters.Single(), expression).Visit(lambdaExpression.Body);
53 :
54 : return Expression.Property(expression, node.Member.Name);
55 : }
56 :
57 0 : protected override Expression VisitLambda<T>(Expression<T> node)
58 : {
59 : return Expression.Lambda(
60 : Visit(node.Body),
61 : node.Parameters.Select(Visit).Cast<ParameterExpression>()
62 : );
63 : }
64 : }
65 : }
|