1 #region License
2 // Copyright (c) 2007 James Newton-King
3 //
4 // Permission is hereby granted, free of charge, to any person
5 // obtaining a copy of this software and associated documentation
6 // files (the "Software"), to deal in the Software without
7 // restriction, including without limitation the rights to use,
8 // copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following
11 // conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 #endregion
25 
26 #if !(NET20 || NET35)
27 using System.Collections.Generic;
28 using System.Linq;
29 using System.Text;
30 using System;
31 using System.Linq.Expressions;
32 using System.Reflection;
33 using Newtonsoft.Json.Serialization;
34 
35 namespace Newtonsoft.Json.Utilities
36 {
37     internal class ExpressionReflectionDelegateFactory : ReflectionDelegateFactory
38     {
39         private static readonly ExpressionReflectionDelegateFactory _instance = new ExpressionReflectionDelegateFactory();
40 
41         internal static ReflectionDelegateFactory Instance
42         {
43             get { return _instance; }
44         }
45 
CreateParameterizedConstructor(MethodBase method)46         public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
47         {
48             ValidationUtils.ArgumentNotNull(method, nameof(method));
49 
50             Type type = typeof(object);
51 
52             ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
53 
54             Expression callExpression = BuildMethodCall(method, type, null, argsParameterExpression);
55 
56             LambdaExpression lambdaExpression = Expression.Lambda(typeof(ObjectConstructor<object>), callExpression, argsParameterExpression);
57 
58             ObjectConstructor<object> compiled = (ObjectConstructor<object>)lambdaExpression.Compile();
59             return compiled;
60         }
61 
CreateMethodCall(MethodBase method)62         public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
63         {
64             ValidationUtils.ArgumentNotNull(method, nameof(method));
65 
66             Type type = typeof(object);
67 
68             ParameterExpression targetParameterExpression = Expression.Parameter(type, "target");
69             ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
70 
71             Expression callExpression = BuildMethodCall(method, type, targetParameterExpression, argsParameterExpression);
72 
73             LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
74 
75             MethodCall<T, object> compiled = (MethodCall<T, object>)lambdaExpression.Compile();
76             return compiled;
77         }
78 
79         private class ByRefParameter
80         {
81             public Expression Value;
82             public ParameterExpression Variable;
83             public bool IsOut;
84         }
85 
BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)86         private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)
87         {
88             ParameterInfo[] parametersInfo = method.GetParameters();
89 
90             Expression[] argsExpression = new Expression[parametersInfo.Length];
91             IList<ByRefParameter> refParameterMap = new List<ByRefParameter>();
92 
93             for (int i = 0; i < parametersInfo.Length; i++)
94             {
95                 ParameterInfo parameter = parametersInfo[i];
96                 Type parameterType = parameter.ParameterType;
97                 bool isByRef = false;
98                 if (parameterType.IsByRef)
99                 {
100                     parameterType = parameterType.GetElementType();
101                     isByRef = true;
102                 }
103 
104                 Expression indexExpression = Expression.Constant(i);
105 
106                 Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
107 
108                 Expression argExpression;
109 
110                 if (parameterType.IsValueType())
111                 {
112                     BinaryExpression ensureValueTypeNotNull = Expression.Coalesce(paramAccessorExpression, Expression.New(parameterType));
113 
114                     argExpression = EnsureCastExpression(ensureValueTypeNotNull, parameterType);
115                 }
116                 else
117                 {
118                     argExpression = EnsureCastExpression(paramAccessorExpression, parameterType);
119                 }
120 
121                 if (isByRef)
122                 {
123                     ParameterExpression variable = Expression.Variable(parameterType);
124                     refParameterMap.Add(new ByRefParameter
125                     {
126                         Value = argExpression,
127                         Variable = variable,
128                         IsOut = parameter.IsOut
129                     });
130 
131                     argExpression = variable;
132                 }
133 
134                 argsExpression[i] = argExpression;
135             }
136 
137             Expression callExpression;
138             if (method.IsConstructor)
139             {
140                 callExpression = Expression.New((ConstructorInfo)method, argsExpression);
141             }
142             else if (method.IsStatic)
143             {
144                 callExpression = Expression.Call((MethodInfo)method, argsExpression);
145             }
146             else
147             {
148                 Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType);
149 
150                 callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression);
151             }
152 
153             if (method is MethodInfo)
154             {
155                 MethodInfo m = (MethodInfo)method;
156                 if (m.ReturnType != typeof(void))
157                 {
158                     callExpression = EnsureCastExpression(callExpression, type);
159                 }
160                 else
161                 {
162                     callExpression = Expression.Block(callExpression, Expression.Constant(null));
163                 }
164             }
165             else
166             {
167                 callExpression = EnsureCastExpression(callExpression, type);
168             }
169 
170             if (refParameterMap.Count > 0)
171             {
172                 IList<ParameterExpression> variableExpressions = new List<ParameterExpression>();
173                 IList<Expression> bodyExpressions = new List<Expression>();
174                 foreach (ByRefParameter p in refParameterMap)
175                 {
176                     if (!p.IsOut)
177                     {
178                         bodyExpressions.Add(Expression.Assign(p.Variable, p.Value));
179                     }
180 
181                     variableExpressions.Add(p.Variable);
182                 }
183 
184                 bodyExpressions.Add(callExpression);
185 
186                 callExpression = Expression.Block(variableExpressions, bodyExpressions);
187             }
188 
189             return callExpression;
190         }
191 
CreateDefaultConstructor(Type type)192         public override Func<T> CreateDefaultConstructor<T>(Type type)
193         {
194             ValidationUtils.ArgumentNotNull(type, "type");
195 
196             // avoid error from expressions compiler because of abstract class
197             if (type.IsAbstract())
198             {
199                 return () => (T)Activator.CreateInstance(type);
200             }
201 
202             try
203             {
204                 Type resultType = typeof(T);
205 
206                 Expression expression = Expression.New(type);
207 
208                 expression = EnsureCastExpression(expression, resultType);
209 
210                 LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T>), expression);
211 
212                 Func<T> compiled = (Func<T>)lambdaExpression.Compile();
213                 return compiled;
214             }
215             catch
216             {
217                 // an error can be thrown if constructor is not valid on Win8
218                 // will have INVOCATION_FLAGS_NON_W8P_FX_API invocation flag
219                 return () => (T)Activator.CreateInstance(type);
220             }
221         }
222 
CreateGet(PropertyInfo propertyInfo)223         public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
224         {
225             ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
226 
227             Type instanceType = typeof(T);
228             Type resultType = typeof(object);
229 
230             ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance");
231             Expression resultExpression;
232 
233             MethodInfo getMethod = propertyInfo.GetGetMethod(true);
234 
235             if (getMethod.IsStatic)
236             {
237                 resultExpression = Expression.MakeMemberAccess(null, propertyInfo);
238             }
239             else
240             {
241                 Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType);
242 
243                 resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo);
244             }
245 
246             resultExpression = EnsureCastExpression(resultExpression, resultType);
247 
248             LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T, object>), resultExpression, parameterExpression);
249 
250             Func<T, object> compiled = (Func<T, object>)lambdaExpression.Compile();
251             return compiled;
252         }
253 
CreateGet(FieldInfo fieldInfo)254         public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
255         {
256             ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
257 
258             ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
259 
260             Expression fieldExpression;
261             if (fieldInfo.IsStatic)
262             {
263                 fieldExpression = Expression.Field(null, fieldInfo);
264             }
265             else
266             {
267                 Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType);
268 
269                 fieldExpression = Expression.Field(sourceExpression, fieldInfo);
270             }
271 
272             fieldExpression = EnsureCastExpression(fieldExpression, typeof(object));
273 
274             Func<T, object> compiled = Expression.Lambda<Func<T, object>>(fieldExpression, sourceParameter).Compile();
275             return compiled;
276         }
277 
CreateSet(FieldInfo fieldInfo)278         public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
279         {
280             ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
281 
282             // use reflection for structs
283             // expression doesn't correctly set value
284             if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly)
285             {
286                 return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(fieldInfo);
287             }
288 
289             ParameterExpression sourceParameterExpression = Expression.Parameter(typeof(T), "source");
290             ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
291 
292             Expression fieldExpression;
293             if (fieldInfo.IsStatic)
294             {
295                 fieldExpression = Expression.Field(null, fieldInfo);
296             }
297             else
298             {
299                 Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType);
300 
301                 fieldExpression = Expression.Field(sourceExpression, fieldInfo);
302             }
303 
304             Expression valueExpression = EnsureCastExpression(valueParameterExpression, fieldExpression.Type);
305 
306             BinaryExpression assignExpression = Expression.Assign(fieldExpression, valueExpression);
307 
308             LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), assignExpression, sourceParameterExpression, valueParameterExpression);
309 
310             Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
311             return compiled;
312         }
313 
CreateSet(PropertyInfo propertyInfo)314         public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
315         {
316             ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
317 
318             // use reflection for structs
319             // expression doesn't correctly set value
320             if (propertyInfo.DeclaringType.IsValueType())
321             {
322                 return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(propertyInfo);
323             }
324 
325             Type instanceType = typeof(T);
326             Type valueType = typeof(object);
327 
328             ParameterExpression instanceParameter = Expression.Parameter(instanceType, "instance");
329 
330             ParameterExpression valueParameter = Expression.Parameter(valueType, "value");
331             Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType);
332 
333             MethodInfo setMethod = propertyInfo.GetSetMethod(true);
334 
335             Expression setExpression;
336             if (setMethod.IsStatic)
337             {
338                 setExpression = Expression.Call(setMethod, readValueParameter);
339             }
340             else
341             {
342                 Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType);
343 
344                 setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter);
345             }
346 
347             LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), setExpression, instanceParameter, valueParameter);
348 
349             Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
350             return compiled;
351         }
352 
EnsureCastExpression(Expression expression, Type targetType)353         private Expression EnsureCastExpression(Expression expression, Type targetType)
354         {
355             Type expressionType = expression.Type;
356 
357             // check if a cast or conversion is required
358             if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType)))
359             {
360                 return expression;
361             }
362 
363             return Expression.Convert(expression, targetType);
364         }
365     }
366 }
367 
368 #endif