You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
15 KiB

  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. #if !(NET20 || NET35)
  26. using System.Collections.Generic;
  27. using System.Linq;
  28. using System.Text;
  29. using System;
  30. using System.Linq.Expressions;
  31. using System.Reflection;
  32. using Newtonsoft.Json.Serialization;
  33. namespace Newtonsoft.Json.Utilities
  34. {
  35. internal class ExpressionReflectionDelegateFactory : ReflectionDelegateFactory
  36. {
  37. private static readonly ExpressionReflectionDelegateFactory _instance = new ExpressionReflectionDelegateFactory();
  38. internal static ReflectionDelegateFactory Instance => _instance;
  39. public override ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
  40. {
  41. ValidationUtils.ArgumentNotNull(method, nameof(method));
  42. Type type = typeof(object);
  43. ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
  44. Expression callExpression = BuildMethodCall(method, type, null, argsParameterExpression);
  45. LambdaExpression lambdaExpression = Expression.Lambda(typeof(ObjectConstructor<object>), callExpression, argsParameterExpression);
  46. ObjectConstructor<object> compiled = (ObjectConstructor<object>)lambdaExpression.Compile();
  47. return compiled;
  48. }
  49. public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method)
  50. {
  51. ValidationUtils.ArgumentNotNull(method, nameof(method));
  52. Type type = typeof(object);
  53. ParameterExpression targetParameterExpression = Expression.Parameter(type, "target");
  54. ParameterExpression argsParameterExpression = Expression.Parameter(typeof(object[]), "args");
  55. Expression callExpression = BuildMethodCall(method, type, targetParameterExpression, argsParameterExpression);
  56. LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall<T, object>), callExpression, targetParameterExpression, argsParameterExpression);
  57. MethodCall<T, object> compiled = (MethodCall<T, object>)lambdaExpression.Compile();
  58. return compiled;
  59. }
  60. private class ByRefParameter
  61. {
  62. public Expression Value;
  63. public ParameterExpression Variable;
  64. public bool IsOut;
  65. }
  66. private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression)
  67. {
  68. ParameterInfo[] parametersInfo = method.GetParameters();
  69. Expression[] argsExpression;
  70. IList<ByRefParameter> refParameterMap;
  71. if (parametersInfo.Length == 0)
  72. {
  73. argsExpression = CollectionUtils.ArrayEmpty<Expression>();
  74. refParameterMap = CollectionUtils.ArrayEmpty<ByRefParameter>();
  75. }
  76. else
  77. {
  78. argsExpression = new Expression[parametersInfo.Length];
  79. refParameterMap = new List<ByRefParameter>();
  80. for (int i = 0; i < parametersInfo.Length; i++)
  81. {
  82. ParameterInfo parameter = parametersInfo[i];
  83. Type parameterType = parameter.ParameterType;
  84. bool isByRef = false;
  85. if (parameterType.IsByRef)
  86. {
  87. parameterType = parameterType.GetElementType();
  88. isByRef = true;
  89. }
  90. Expression indexExpression = Expression.Constant(i);
  91. Expression paramAccessorExpression = Expression.ArrayIndex(argsParameterExpression, indexExpression);
  92. Expression argExpression = EnsureCastExpression(paramAccessorExpression, parameterType, !isByRef);
  93. if (isByRef)
  94. {
  95. ParameterExpression variable = Expression.Variable(parameterType);
  96. refParameterMap.Add(new ByRefParameter {Value = argExpression, Variable = variable, IsOut = parameter.IsOut});
  97. argExpression = variable;
  98. }
  99. argsExpression[i] = argExpression;
  100. }
  101. }
  102. Expression callExpression;
  103. if (method.IsConstructor)
  104. {
  105. callExpression = Expression.New((ConstructorInfo)method, argsExpression);
  106. }
  107. else if (method.IsStatic)
  108. {
  109. callExpression = Expression.Call((MethodInfo)method, argsExpression);
  110. }
  111. else
  112. {
  113. Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType);
  114. callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression);
  115. }
  116. MethodInfo m = method as MethodInfo;
  117. if (m != null)
  118. {
  119. if (m.ReturnType != typeof(void))
  120. {
  121. callExpression = EnsureCastExpression(callExpression, type);
  122. }
  123. else
  124. {
  125. callExpression = Expression.Block(callExpression, Expression.Constant(null));
  126. }
  127. }
  128. else
  129. {
  130. callExpression = EnsureCastExpression(callExpression, type);
  131. }
  132. if (refParameterMap.Count > 0)
  133. {
  134. IList<ParameterExpression> variableExpressions = new List<ParameterExpression>();
  135. IList<Expression> bodyExpressions = new List<Expression>();
  136. foreach (ByRefParameter p in refParameterMap)
  137. {
  138. if (!p.IsOut)
  139. {
  140. bodyExpressions.Add(Expression.Assign(p.Variable, p.Value));
  141. }
  142. variableExpressions.Add(p.Variable);
  143. }
  144. bodyExpressions.Add(callExpression);
  145. callExpression = Expression.Block(variableExpressions, bodyExpressions);
  146. }
  147. return callExpression;
  148. }
  149. public override Func<T> CreateDefaultConstructor<T>(Type type)
  150. {
  151. ValidationUtils.ArgumentNotNull(type, "type");
  152. // avoid error from expressions compiler because of abstract class
  153. if (type.IsAbstract())
  154. {
  155. return () => (T)Activator.CreateInstance(type);
  156. }
  157. try
  158. {
  159. Type resultType = typeof(T);
  160. Expression expression = Expression.New(type);
  161. expression = EnsureCastExpression(expression, resultType);
  162. LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T>), expression);
  163. Func<T> compiled = (Func<T>)lambdaExpression.Compile();
  164. return compiled;
  165. }
  166. catch
  167. {
  168. // an error can be thrown if constructor is not valid on Win8
  169. // will have INVOCATION_FLAGS_NON_W8P_FX_API invocation flag
  170. return () => (T)Activator.CreateInstance(type);
  171. }
  172. }
  173. public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo)
  174. {
  175. ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
  176. Type instanceType = typeof(T);
  177. Type resultType = typeof(object);
  178. ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance");
  179. Expression resultExpression;
  180. MethodInfo getMethod = propertyInfo.GetGetMethod(true);
  181. if (getMethod.IsStatic)
  182. {
  183. resultExpression = Expression.MakeMemberAccess(null, propertyInfo);
  184. }
  185. else
  186. {
  187. Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType);
  188. resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo);
  189. }
  190. resultExpression = EnsureCastExpression(resultExpression, resultType);
  191. LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T, object>), resultExpression, parameterExpression);
  192. Func<T, object> compiled = (Func<T, object>)lambdaExpression.Compile();
  193. return compiled;
  194. }
  195. public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo)
  196. {
  197. ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
  198. ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
  199. Expression fieldExpression;
  200. if (fieldInfo.IsStatic)
  201. {
  202. fieldExpression = Expression.Field(null, fieldInfo);
  203. }
  204. else
  205. {
  206. Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType);
  207. fieldExpression = Expression.Field(sourceExpression, fieldInfo);
  208. }
  209. fieldExpression = EnsureCastExpression(fieldExpression, typeof(object));
  210. Func<T, object> compiled = Expression.Lambda<Func<T, object>>(fieldExpression, sourceParameter).Compile();
  211. return compiled;
  212. }
  213. public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo)
  214. {
  215. ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo));
  216. // use reflection for structs
  217. // expression doesn't correctly set value
  218. if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly)
  219. {
  220. return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(fieldInfo);
  221. }
  222. ParameterExpression sourceParameterExpression = Expression.Parameter(typeof(T), "source");
  223. ParameterExpression valueParameterExpression = Expression.Parameter(typeof(object), "value");
  224. Expression fieldExpression;
  225. if (fieldInfo.IsStatic)
  226. {
  227. fieldExpression = Expression.Field(null, fieldInfo);
  228. }
  229. else
  230. {
  231. Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType);
  232. fieldExpression = Expression.Field(sourceExpression, fieldInfo);
  233. }
  234. Expression valueExpression = EnsureCastExpression(valueParameterExpression, fieldExpression.Type);
  235. BinaryExpression assignExpression = Expression.Assign(fieldExpression, valueExpression);
  236. LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), assignExpression, sourceParameterExpression, valueParameterExpression);
  237. Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
  238. return compiled;
  239. }
  240. public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo)
  241. {
  242. ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
  243. // use reflection for structs
  244. // expression doesn't correctly set value
  245. if (propertyInfo.DeclaringType.IsValueType())
  246. {
  247. return LateBoundReflectionDelegateFactory.Instance.CreateSet<T>(propertyInfo);
  248. }
  249. Type instanceType = typeof(T);
  250. Type valueType = typeof(object);
  251. ParameterExpression instanceParameter = Expression.Parameter(instanceType, "instance");
  252. ParameterExpression valueParameter = Expression.Parameter(valueType, "value");
  253. Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType);
  254. MethodInfo setMethod = propertyInfo.GetSetMethod(true);
  255. Expression setExpression;
  256. if (setMethod.IsStatic)
  257. {
  258. setExpression = Expression.Call(setMethod, readValueParameter);
  259. }
  260. else
  261. {
  262. Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType);
  263. setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter);
  264. }
  265. LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action<T, object>), setExpression, instanceParameter, valueParameter);
  266. Action<T, object> compiled = (Action<T, object>)lambdaExpression.Compile();
  267. return compiled;
  268. }
  269. private Expression EnsureCastExpression(Expression expression, Type targetType, bool allowWidening = false)
  270. {
  271. Type expressionType = expression.Type;
  272. // check if a cast or conversion is required
  273. if (expressionType == targetType || (!expressionType.IsValueType() && targetType.IsAssignableFrom(expressionType)))
  274. {
  275. return expression;
  276. }
  277. if (targetType.IsValueType())
  278. {
  279. Expression convert = Expression.Unbox(expression, targetType);
  280. if (allowWidening && targetType.IsPrimitive())
  281. {
  282. MethodInfo toTargetTypeMethod = typeof(Convert)
  283. .GetMethod("To" + targetType.Name, new[] { typeof(object) });
  284. if (toTargetTypeMethod != null)
  285. {
  286. convert = Expression.Condition(
  287. Expression.TypeIs(expression, targetType),
  288. convert,
  289. Expression.Call(toTargetTypeMethod, expression));
  290. }
  291. }
  292. return Expression.Condition(
  293. Expression.Equal(expression, Expression.Constant(null, typeof(object))),
  294. Expression.Default(targetType),
  295. convert);
  296. }
  297. return Expression.Convert(expression, targetType);
  298. }
  299. }
  300. }
  301. #endif