Skip to content

Commit bf7cbf7

Browse files
committed
Optimising single parameter expression replacement
1 parent ae26708 commit bf7cbf7

File tree

1 file changed

+81
-46
lines changed

1 file changed

+81
-46
lines changed

AgileMapper/Extensions/Internal/ExpressionExtensions.Replace.cs

Lines changed: 81 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,37 @@
44
using System.Collections.Generic;
55
using System.Linq;
66
using System.Linq.Expressions;
7+
using static System.Linq.Expressions.ExpressionType;
78

89
internal static partial class ExpressionExtensions
910
{
10-
public static Expression ReplaceParameterWith(this LambdaExpression lambda, Expression replacement)
11-
=> ReplaceParametersWith(lambda, replacement);
12-
1311
public static Expression ReplaceParametersWith(this LambdaExpression lambda, params Expression[] replacements)
1412
{
1513
if (lambda.Parameters.HasOne())
1614
{
17-
return lambda.Body.Replace(lambda.Parameters[0], replacements[0]);
15+
return lambda.ReplaceParameterWith(replacements.First());
1816
}
1917

2018
var replacementsByParameter = lambda
2119
.Parameters
22-
.Cast<Expression>()
2320
.Select((p, i) => new { Parameter = p, Replacement = replacements[i] })
24-
.ToDictionary(d => d.Parameter, d => d.Replacement);
21+
.ToDictionary(d => (Expression)d.Parameter, d => d.Replacement);
2522

2623
return lambda.Body.Replace(replacementsByParameter);
2724
}
2825

26+
public static Expression ReplaceParameterWith(this LambdaExpression lambda, Expression replacement)
27+
=> ReplaceParameter(lambda.Body, lambda.Parameters[0], replacement);
28+
29+
private static TExpression ReplaceParameter<TExpression>(
30+
TExpression expression,
31+
Expression parameter,
32+
Expression replacement)
33+
where TExpression : Expression
34+
{
35+
return new ParameterReplacer(parameter, replacement).ReplaceIn(expression);
36+
}
37+
2938
public static TExpression Replace<TExpression>(
3039
this TExpression expression,
3140
Expression target,
@@ -38,6 +47,11 @@ public static TExpression Replace<TExpression>(
3847
return null;
3948
}
4049

50+
if (target.NodeType == Parameter)
51+
{
52+
return ReplaceParameter(expression, target, replacement);
53+
}
54+
4155
return new ExpressionReplacer(
4256
target,
4357
replacement,
@@ -65,6 +79,27 @@ public static TExpression Replace<TExpression>(
6579
return replacer.Replace<TExpression>(expression);
6680
}
6781

82+
private class ParameterReplacer : ExpressionVisitor
83+
{
84+
private readonly Expression _parameterToReplace;
85+
private readonly Expression _replacement;
86+
87+
public ParameterReplacer(Expression parameterToReplace, Expression replacement)
88+
{
89+
_parameterToReplace = parameterToReplace;
90+
_replacement = replacement;
91+
}
92+
93+
public TExpression ReplaceIn<TExpression>(TExpression expression)
94+
where TExpression : Expression
95+
{
96+
return VisitAndConvert(expression, nameof(ParameterReplacer));
97+
}
98+
99+
protected override Expression VisitParameter(ParameterExpression parameter)
100+
=> parameter == _parameterToReplace ? _replacement : parameter;
101+
}
102+
68103
private class ExpressionReplacer
69104
{
70105
private readonly Dictionary<Expression, Expression> _replacementsByTarget;
@@ -99,82 +134,82 @@ private Expression ReplaceIn(Expression expression)
99134
{
100135
switch (expression.NodeType)
101136
{
102-
case ExpressionType.Add:
103-
case ExpressionType.And:
104-
case ExpressionType.AndAlso:
105-
case ExpressionType.Assign:
106-
case ExpressionType.Coalesce:
107-
case ExpressionType.Divide:
108-
case ExpressionType.Equal:
109-
case ExpressionType.GreaterThan:
110-
case ExpressionType.GreaterThanOrEqual:
111-
case ExpressionType.LessThan:
112-
case ExpressionType.LessThanOrEqual:
113-
case ExpressionType.Modulo:
114-
case ExpressionType.Multiply:
115-
case ExpressionType.NotEqual:
116-
case ExpressionType.Or:
117-
case ExpressionType.OrElse:
118-
case ExpressionType.Subtract:
137+
case Add:
138+
case And:
139+
case AndAlso:
140+
case Assign:
141+
case Coalesce:
142+
case Divide:
143+
case Equal:
144+
case GreaterThan:
145+
case GreaterThanOrEqual:
146+
case LessThan:
147+
case LessThanOrEqual:
148+
case Modulo:
149+
case Multiply:
150+
case NotEqual:
151+
case Or:
152+
case OrElse:
153+
case Subtract:
119154
return ReplaceIn((BinaryExpression)expression);
120155

121-
case ExpressionType.Block:
156+
case Block:
122157
return ReplaceIn((BlockExpression)expression);
123158

124-
case ExpressionType.Call:
159+
case Call:
125160
return ReplaceIn((MethodCallExpression)expression);
126161

127-
case ExpressionType.Conditional:
162+
case Conditional:
128163
return ReplaceIn((ConditionalExpression)expression);
129164

130165
case ExpressionType.Convert:
131-
case ExpressionType.IsFalse:
132-
case ExpressionType.IsTrue:
133-
case ExpressionType.Not:
134-
case ExpressionType.Throw:
135-
case ExpressionType.TypeAs:
166+
case IsFalse:
167+
case IsTrue:
168+
case Not:
169+
case Throw:
170+
case TypeAs:
136171
return ReplaceIn((UnaryExpression)expression);
137172

138-
case ExpressionType.Goto:
173+
case Goto:
139174
return ReplaceIn((GotoExpression)expression);
140175

141-
case ExpressionType.Index:
176+
case Index:
142177
return ReplaceIn((IndexExpression)expression);
143178

144-
case ExpressionType.Invoke:
179+
case Invoke:
145180
return ReplaceIn((InvocationExpression)expression);
146181

147-
case ExpressionType.Label:
182+
case Label:
148183
return ReplaceIn((LabelExpression)expression);
149184

150-
case ExpressionType.Lambda:
185+
case Lambda:
151186
return ReplaceIn((LambdaExpression)expression);
152187

153-
case ExpressionType.ListInit:
188+
case ListInit:
154189
return ReplaceIn((ListInitExpression)expression);
155190

156-
case ExpressionType.Loop:
191+
case Loop:
157192
return ReplaceIn((LoopExpression)expression);
158193

159-
case ExpressionType.MemberAccess:
194+
case MemberAccess:
160195
return ReplaceIn((MemberExpression)expression);
161196

162-
case ExpressionType.MemberInit:
197+
case MemberInit:
163198
return ReplaceIn((MemberInitExpression)expression);
164199

165-
case ExpressionType.New:
200+
case New:
166201
return ReplaceIn((NewExpression)expression);
167202

168-
case ExpressionType.NewArrayInit:
203+
case NewArrayInit:
169204
return ReplaceIn((NewArrayExpression)expression);
170205

171-
case ExpressionType.Parameter:
206+
case Parameter:
172207
return ReplaceIn((ParameterExpression)expression);
173208

174-
case ExpressionType.TypeIs:
209+
case TypeIs:
175210
return ReplaceIn((TypeBinaryExpression)expression);
176211

177-
case ExpressionType.Try:
212+
case Try:
178213
return ReplaceIn((TryExpression)expression);
179214
}
180215

@@ -293,7 +328,7 @@ private Expression ReplaceIn<TExpression>(TExpression expression, Func<TExpressi
293328
return null;
294329
}
295330

296-
if (expression.NodeType == ExpressionType.Default)
331+
if (expression.NodeType == Default)
297332
{
298333
return expression;
299334
}

0 commit comments

Comments
 (0)