|
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
4 | 4 | using System.Linq.Expressions; |
5 | | -using System.Reflection; |
6 | 5 | using NHibernate.Linq.Visitors; |
7 | 6 | using NHibernate.Util; |
8 | 7 |
|
9 | 8 | namespace NHibernate.Linq |
10 | 9 | { |
11 | 10 | public class DmlExpressionRewriter |
12 | 11 | { |
13 | | - static readonly ConstructorInfo DictionaryConstructorInfo = typeof(Dictionary<string, object>).GetConstructor(new[] {typeof(int)}); |
14 | | - |
15 | | - static readonly MethodInfo DictionaryAddMethodInfo = ReflectHelper.GetMethod<Dictionary<string, object>>(d => d.Add(null, null)); |
16 | | - |
17 | 12 | readonly IReadOnlyCollection<ParameterExpression> _parameters; |
18 | 13 | readonly Dictionary<string, Expression> _assignments = new Dictionary<string, Expression>(); |
19 | 14 |
|
@@ -80,39 +75,25 @@ void AddSettersFromAssignment(MemberAssignment assignment, string path) |
80 | 75 | } |
81 | 76 |
|
82 | 77 | /// <summary> |
83 | | - /// Converts the assignments into a lambda expression, which creates a Dictionary<string,object%gt;. |
| 78 | + /// Converts the assignments into block of assignments |
84 | 79 | /// </summary> |
85 | 80 | /// <param name="assignments"></param> |
86 | 81 | /// <returns>A lambda expression representing the assignments.</returns> |
87 | | - static LambdaExpression ConvertAssignmentsToDictionaryExpression<TSource>(IReadOnlyDictionary<string, Expression> assignments) |
| 82 | + static LambdaExpression ConvertAssignmentsToBlockExpression<TSource>(IReadOnlyDictionary<string, Expression> assignments) |
88 | 83 | { |
89 | 84 | var param = Expression.Parameter(typeof(TSource)); |
90 | | - var inits = new List<ElementInit>(); |
| 85 | + var variableAndAssignmentDic = new Dictionary<ParameterExpression, Expression>(assignments.Count); |
91 | 86 | foreach (var set in assignments) |
92 | 87 | { |
93 | 88 | var setter = set.Value; |
94 | 89 | if (setter is LambdaExpression setterLambda) |
95 | 90 | setter = setterLambda.Body.Replace(setterLambda.Parameters.First(), param); |
96 | | - inits.Add( |
97 | | - Expression.ElementInit( |
98 | | - DictionaryAddMethodInfo, |
99 | | - Expression.Constant(set.Key), |
100 | | - Expression.Convert(setter, typeof(object)))); |
| 91 | + |
| 92 | + var var = Expression.Variable(typeof(object), set.Key); |
| 93 | + variableAndAssignmentDic[var] = Expression.Assign(var, Expression.Convert(setter, typeof(object))); |
101 | 94 | } |
102 | 95 |
|
103 | | - //The ListInit is intentionally "infected" with the lambda parameter (param), in the form of an IIF. |
104 | | - //The only relevance is to make sure that the ListInit is not evaluated by the PartialEvaluatingExpressionTreeVisitor, |
105 | | - //which could turn it into a Constant |
106 | | - var listInit = Expression.ListInit( |
107 | | - Expression.New( |
108 | | - DictionaryConstructorInfo, |
109 | | - Expression.Condition( |
110 | | - Expression.Equal(param, Expression.Constant(null, typeof(TSource))), |
111 | | - Expression.Constant(assignments.Count), |
112 | | - Expression.Constant(assignments.Count))), |
113 | | - inits); |
114 | | - |
115 | | - return Expression.Lambda(listInit, param); |
| 96 | + return Expression.Lambda(Expression.Block(variableAndAssignmentDic.Keys, variableAndAssignmentDic.Values), param); |
116 | 97 | } |
117 | 98 |
|
118 | 99 | public static Expression PrepareExpression<TSource, TTarget>(Expression sourceExpression, Expression<Func<TSource, TTarget>> expression) |
@@ -151,7 +132,7 @@ public static Expression PrepareExpressionFromAnonymous<TSource>(Expression sour |
151 | 132 |
|
152 | 133 | public static Expression PrepareExpression<TSource>(Expression sourceExpression, IReadOnlyDictionary<string, Expression> assignments) |
153 | 134 | { |
154 | | - var lambda = ConvertAssignmentsToDictionaryExpression<TSource>(assignments); |
| 135 | + var lambda = ConvertAssignmentsToBlockExpression<TSource>(assignments); |
155 | 136 |
|
156 | 137 | return Expression.Call( |
157 | 138 | ReflectionCache.QueryableMethods.SelectDefinition.MakeGenericMethod(typeof(TSource), lambda.Body.Type), |
|
0 commit comments