PageRenderTime 65ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/QbservableProvider/Source/QbservableProvider/Expressions/SerializableExpressionConverter.cs

#
C# | 311 lines | 283 code | 21 blank | 7 comment | 91 complexity | 38a9216f7fd13a74c657add99da984a4 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. namespace QbservableProvider.Expressions
  7. {
  8. internal sealed class SerializableExpressionConverter
  9. {
  10. private const List<Tuple<Tuple<MethodInfo, Type[]>, IList<SerializableExpression>>> noInitializers = null;
  11. private const SerializableExpression noExpression = null;
  12. private const IList<object> noRecursion = null;
  13. private readonly Dictionary<Expression, SerializableExpression> serialized = new Dictionary<Expression, SerializableExpression>();
  14. private BinaryExpression binary;
  15. private BlockExpression block;
  16. private ConditionalExpression conditional;
  17. private ConstantExpression constant;
  18. private DefaultExpression @default;
  19. private GotoExpression @goto;
  20. private IndexExpression index;
  21. private InvocationExpression invocation;
  22. private LabelExpression label;
  23. private LambdaExpression lambda;
  24. private ListInitExpression listInit;
  25. private LoopExpression loop;
  26. private MemberExpression member;
  27. private MemberInitExpression memberInit;
  28. private MethodCallExpression methodCall;
  29. private NewArrayExpression newArray;
  30. private NewExpression @new;
  31. private ParameterExpression parameter;
  32. private RuntimeVariablesExpression runtimeVariables;
  33. private SwitchExpression @switch;
  34. private TryExpression @try;
  35. private TypeBinaryExpression typeBinary;
  36. private UnaryExpression unary;
  37. public IList<TSerializableExpression> Convert<TSerializableExpression>(IEnumerable<Expression> expressions)
  38. where TSerializableExpression : SerializableExpression
  39. {
  40. if (expressions == null)
  41. {
  42. return new List<TSerializableExpression>(0);
  43. }
  44. else
  45. {
  46. return expressions.Select(Convert).Cast<TSerializableExpression>().ToList();
  47. }
  48. }
  49. public IList<SerializableExpression> Convert(IEnumerable<Expression> expressions)
  50. {
  51. if (expressions == null)
  52. {
  53. return new List<SerializableExpression>(0);
  54. }
  55. else
  56. {
  57. return expressions.Select(Convert).ToList();
  58. }
  59. }
  60. public TSerializableExpression Convert<TSerializableExpression>(Expression expression)
  61. where TSerializableExpression : SerializableExpression
  62. {
  63. return (TSerializableExpression) Convert(expression);
  64. }
  65. public SerializableExpression Convert(Expression expression)
  66. {
  67. if (expression == null)
  68. {
  69. return null;
  70. }
  71. else if (serialized.ContainsKey(expression))
  72. {
  73. /* Caching is required to maintain object references during serialization.
  74. * See the comments on SerializableExpression.ConvertWithCache for more info.
  75. */
  76. return serialized[expression];
  77. }
  78. else if ((methodCall = expression as MethodCallExpression) != null)
  79. {
  80. return serialized[expression] = new SerializableMethodCallExpression(methodCall, this);
  81. }
  82. else if ((lambda = expression as LambdaExpression) != null)
  83. {
  84. return serialized[expression] = new SerializableLambdaExpression(lambda, this);
  85. }
  86. else if ((constant = expression as ConstantExpression) != null)
  87. {
  88. return serialized[expression] = new SerializableConstantExpression(constant, this);
  89. }
  90. else if ((member = expression as MemberExpression) != null)
  91. {
  92. return serialized[expression] = new SerializableMemberExpression(member, this);
  93. }
  94. else if ((binary = expression as BinaryExpression) != null)
  95. {
  96. return serialized[expression] = new SerializableBinaryExpression(binary, this);
  97. }
  98. else if ((block = expression as BlockExpression) != null)
  99. {
  100. return serialized[expression] = new SerializableBlockExpression(block, this);
  101. }
  102. else if ((conditional = expression as ConditionalExpression) != null)
  103. {
  104. return serialized[expression] = new SerializableConditionalExpression(conditional, this);
  105. }
  106. else if ((@default = expression as DefaultExpression) != null)
  107. {
  108. return serialized[expression] = new SerializableDefaultExpression(@default, this);
  109. }
  110. else if ((@goto = expression as GotoExpression) != null)
  111. {
  112. return serialized[expression] = new SerializableGotoExpression(@goto, this);
  113. }
  114. else if ((index = expression as IndexExpression) != null)
  115. {
  116. return serialized[expression] = new SerializableIndexExpression(index, this);
  117. }
  118. else if ((invocation = expression as InvocationExpression) != null)
  119. {
  120. return serialized[expression] = new SerializableInvocationExpression(invocation, this);
  121. }
  122. else if ((label = expression as LabelExpression) != null)
  123. {
  124. return serialized[expression] = new SerializableLabelExpression(label, this);
  125. }
  126. else if ((listInit = expression as ListInitExpression) != null)
  127. {
  128. return serialized[expression] = new SerializableListInitExpression(listInit, this);
  129. }
  130. else if ((loop = expression as LoopExpression) != null)
  131. {
  132. return serialized[expression] = new SerializableLoopExpression(loop, this);
  133. }
  134. else if ((memberInit = expression as MemberInitExpression) != null)
  135. {
  136. return serialized[expression] = new SerializableMemberInitExpression(memberInit, this);
  137. }
  138. else if ((newArray = expression as NewArrayExpression) != null)
  139. {
  140. return serialized[expression] = new SerializableNewArrayExpression(newArray, this);
  141. }
  142. else if ((@new = expression as NewExpression) != null)
  143. {
  144. return serialized[expression] = new SerializableNewExpression(@new, this);
  145. }
  146. else if ((parameter = expression as ParameterExpression) != null)
  147. {
  148. return serialized[expression] = new SerializableParameterExpression(parameter, this);
  149. }
  150. else if ((runtimeVariables = expression as RuntimeVariablesExpression) != null)
  151. {
  152. return serialized[expression] = new SerializableRuntimeVariablesExpression(runtimeVariables, this);
  153. }
  154. else if ((@switch = expression as SwitchExpression) != null)
  155. {
  156. return serialized[expression] = new SerializableSwitchExpression(@switch, this);
  157. }
  158. else if ((@try = expression as TryExpression) != null)
  159. {
  160. return serialized[expression] = new SerializableTryExpression(@try, this);
  161. }
  162. else if ((typeBinary = expression as TypeBinaryExpression) != null)
  163. {
  164. return serialized[expression] = new SerializableTypeBinaryExpression(typeBinary, this);
  165. }
  166. else if ((unary = expression as UnaryExpression) != null)
  167. {
  168. return serialized[expression] = new SerializableUnaryExpression(unary, this);
  169. }
  170. else
  171. {
  172. throw new ArgumentOutOfRangeException("expression");
  173. }
  174. }
  175. public Expression Convert(SerializableExpression expression)
  176. {
  177. return expression.TryConvert();
  178. }
  179. // Workaround for a bug deserializing closed generic methods.
  180. // https://connect.microsoft.com/VisualStudio/feedback/details/736993/bound-generic-methodinfo-throws-argumentnullexception-on-deserialization
  181. public Tuple<MethodInfo, Type[]> Convert(MethodInfo method)
  182. {
  183. if (method != null && method.IsGenericMethod && !method.IsGenericMethodDefinition)
  184. {
  185. return Tuple.Create(method.GetGenericMethodDefinition(), method.GetGenericArguments());
  186. }
  187. else
  188. {
  189. return Tuple.Create(method, (Type[]) null);
  190. }
  191. }
  192. // Workaround for a bug deserializing closed generic methods.
  193. // https://connect.microsoft.com/VisualStudio/feedback/details/736993/bound-generic-methodinfo-throws-argumentnullexception-on-deserialization
  194. public static MethodInfo Convert(Tuple<MethodInfo, Type[]> method)
  195. {
  196. if (method.Item2 == null)
  197. {
  198. return method.Item1;
  199. }
  200. else
  201. {
  202. return method.Item1.MakeGenericMethod(method.Item2);
  203. }
  204. }
  205. public Tuple<MemberInfo, Type[]> Convert(MemberInfo member)
  206. {
  207. var method = member as MethodInfo;
  208. if (method != null)
  209. {
  210. var converted = Convert(method);
  211. return Tuple.Create((MemberInfo) converted.Item1, converted.Item2);
  212. }
  213. else
  214. {
  215. return Tuple.Create(member, (Type[]) null);
  216. }
  217. }
  218. public static MemberInfo Convert(Tuple<MemberInfo, Type[]> member)
  219. {
  220. var method = member.Item1 as MethodInfo;
  221. if (method != null)
  222. {
  223. return Convert(Tuple.Create(method, member.Item2));
  224. }
  225. else
  226. {
  227. return member.Item1;
  228. }
  229. }
  230. public IList<Tuple<MemberInfo, Type[]>> Convert(IEnumerable<MemberInfo> members)
  231. {
  232. if (members == null)
  233. {
  234. return new List<Tuple<MemberInfo, Type[]>>(0);
  235. }
  236. else
  237. {
  238. return members.Select(Convert).ToList();
  239. }
  240. }
  241. public Tuple<Tuple<MemberInfo, Type[]>, MemberBindingType, SerializableExpression, List<Tuple<Tuple<MethodInfo, Type[]>, IList<SerializableExpression>>>, IList<object>> Convert(MemberBinding binding)
  242. {
  243. switch (binding.BindingType)
  244. {
  245. case MemberBindingType.Assignment:
  246. var assign = (MemberAssignment) binding;
  247. return Tuple.Create(
  248. Convert(binding.Member),
  249. binding.BindingType,
  250. Convert(assign.Expression),
  251. noInitializers,
  252. noRecursion);
  253. case MemberBindingType.ListBinding:
  254. var list = (MemberListBinding) binding;
  255. return Tuple.Create(
  256. Convert(binding.Member),
  257. binding.BindingType,
  258. noExpression,
  259. list.Initializers.Select(i => Tuple.Create(Convert(i.AddMethod), Convert(i.Arguments))).ToList(),
  260. noRecursion);
  261. case MemberBindingType.MemberBinding:
  262. var member = (MemberMemberBinding) binding;
  263. return Tuple.Create(
  264. Convert(binding.Member),
  265. binding.BindingType,
  266. noExpression,
  267. noInitializers,
  268. (IList<object>) member.Bindings.Select(Convert).ToList());
  269. default:
  270. throw new InvalidOperationException("Unknown member binding type.");
  271. }
  272. }
  273. public static MemberBinding Convert(Tuple<Tuple<MemberInfo, Type[]>, MemberBindingType, SerializableExpression, List<Tuple<Tuple<MethodInfo, Type[]>, IList<SerializableExpression>>>, IList<object>> data)
  274. {
  275. switch (data.Item2)
  276. {
  277. case MemberBindingType.Assignment:
  278. return Expression.Bind(Convert(data.Item1), data.Item3.TryConvert());
  279. case MemberBindingType.ListBinding:
  280. return Expression.ListBind(Convert(data.Item1), data.Item4.Select(i => Expression.ElementInit(Convert(i.Item1), i.Item2.TryConvert())));
  281. case MemberBindingType.MemberBinding:
  282. return Expression.MemberBind(Convert(data.Item1), data.Item5
  283. .Cast<Tuple<Tuple<MemberInfo, Type[]>, MemberBindingType, SerializableExpression, List<Tuple<Tuple<MethodInfo, Type[]>, IList<SerializableExpression>>>, IList<object>>>()
  284. .Select(Convert));
  285. default:
  286. throw new InvalidOperationException("Unknown member binding type.");
  287. }
  288. }
  289. }
  290. }