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