Редактировал(а) Alexandr Fokin 2023/02/15 13:57

Последние авторы
1 {{code language="c#"}}
2 public class ExpressionMapper2<TEntity, TValue>
3 {
4 private readonly Dictionary<
5 string,
6 TValue
7 > Mapping;
8
9 private readonly Func<IEnumerable<Expression>, string> KeySelector;
10 private static readonly Func<IEnumerable<Expression>, string> DefaultKeySelector =
11 (e) =>
12 {
13 var expression = e.First(e2 => e2 is MemberExpression) as MemberExpression;
14 return expression.Member.Name;
15 };
16
17 public ExpressionMapper2(
18 IEnumerable<(string key, TValue value)> source,
19 Func<IEnumerable<Expression>, string>? keySelector = null
20 )
21 {
22 KeySelector = keySelector ?? DefaultKeySelector;
23 Mapping = source.ToDictionary(
24 e => e.key,
25 e => e.value
26 );
27 }
28 public ExpressionMapper2(
29 IEnumerable<(Expression<Func<TEntity, object>> keyExpression, TValue value)> source,
30 Func<IEnumerable<Expression>, string>? keySelector = null
31 )
32 {
33 KeySelector = keySelector ?? DefaultKeySelector;
34 Mapping = source.ToDictionary(
35 e => GetKey(e.keyExpression),
36 e => e.value
37 );
38 }
39
40
41 private string GetKey(Expression expression)
42 {
43 Visitor visitor = new Visitor();
44 visitor.Visit(expression);
45 var key = KeySelector(visitor.ExpressionList);
46 return key;
47 }
48
49 public bool TryGetValue<T>(
50 Expression<Func<TEntity, T>> expression,
51 out TValue value
52 )
53 {
54 var key = GetKey(expression);
55 return Mapping.TryGetValue(
56 key,
57 out value
58 );
59 }
60
61 public TValue GetValue<T>(
62 Expression<Func<TEntity, T>> expression
63 )
64 {
65 if (TryGetValue(expression, out var value))
66 {
67 return value;
68 }
69 else
70 {
71 throw new KeyNotFoundException();
72 }
73 }
74
75 // Можно сделать более эффективную и строгую реализацию
76 // для примера наиболее простая и общая
77 private sealed class Visitor
78 : ExpressionVisitor
79 {
80 public List<Expression> ExpressionList { get; private set; }
81 = new List<Expression>();
82
83
84 [return: NotNullIfNotNull("node")]
85 public override Expression? Visit(
86 Expression? node
87 )
88 {
89 ExpressionList.Add(node);
90 return base.Visit(node);
91 }
92 }
93
94 public static Builder CreateBuilder()
95 {
96 return new Builder();
97 }
98
99 public class Builder
100 {
101 private Func<IEnumerable<Expression>, string> KeySelector = DefaultKeySelector;
102 private List<(Expression, TValue)> Rules = new List<(Expression, TValue)>();
103
104
105 public Builder SetKeySelector(
106 Func<IEnumerable<Expression>, string> keySelector
107 )
108 {
109 KeySelector = keySelector;
110 return this;
111 }
112
113 public Builder AddRule<T>(
114 Expression<Func<TEntity, T>> rule,
115 TValue value
116 )
117 {
118 Rules.Add((rule, value));
119 return this;
120 }
121
122
123 public ExpressionMapper2<TEntity, TValue> Build()
124 {
125 (string key, TValue value)[] rules = new (string key, TValue value)[Rules.Count];
126 {
127 Visitor visitor = new Visitor();
128 int i = 0;
129 foreach (var elem in Rules)
130 {
131 visitor.Visit(elem.Item1);
132 var key = KeySelector(visitor.ExpressionList);
133 visitor.ExpressionList.Clear();
134
135 rules[i] = (key, elem.Item2);
136 i++;
137 }
138 }
139
140 return new ExpressionMapper2<TEntity, TValue>(
141 rules,
142 KeySelector
143 );
144 }
145 }
146 }
147 {{/code}}