ExpressionTransformer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //
  2. // ExpressionTransformer.cs
  3. //
  4. // Authors:
  5. // Roei Erez ([email protected])
  6. // Jb Evain ([email protected])
  7. //
  8. // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections.ObjectModel;
  31. using System.Collections.Generic;
  32. using System.Linq.Expressions;
  33. namespace System.Linq.Expressions {
  34. abstract class ExpressionTransformer {
  35. public Expression Transform (Expression expression)
  36. {
  37. return Visit (expression);
  38. }
  39. protected virtual Expression Visit (Expression exp)
  40. {
  41. if (exp == null) return exp;
  42. switch (exp.NodeType) {
  43. case ExpressionType.Negate:
  44. case ExpressionType.NegateChecked:
  45. case ExpressionType.Not:
  46. case ExpressionType.Convert:
  47. case ExpressionType.ConvertChecked:
  48. case ExpressionType.ArrayLength:
  49. case ExpressionType.Quote:
  50. case ExpressionType.TypeAs:
  51. case ExpressionType.UnaryPlus:
  52. return this.VisitUnary ((UnaryExpression) exp);
  53. case ExpressionType.Add:
  54. case ExpressionType.AddChecked:
  55. case ExpressionType.Subtract:
  56. case ExpressionType.SubtractChecked:
  57. case ExpressionType.Multiply:
  58. case ExpressionType.MultiplyChecked:
  59. case ExpressionType.Divide:
  60. case ExpressionType.Power:
  61. case ExpressionType.Modulo:
  62. case ExpressionType.And:
  63. case ExpressionType.AndAlso:
  64. case ExpressionType.Or:
  65. case ExpressionType.OrElse:
  66. case ExpressionType.LessThan:
  67. case ExpressionType.LessThanOrEqual:
  68. case ExpressionType.GreaterThan:
  69. case ExpressionType.GreaterThanOrEqual:
  70. case ExpressionType.Equal:
  71. case ExpressionType.NotEqual:
  72. case ExpressionType.Coalesce:
  73. case ExpressionType.ArrayIndex:
  74. case ExpressionType.RightShift:
  75. case ExpressionType.LeftShift:
  76. case ExpressionType.ExclusiveOr:
  77. return this.VisitBinary ((BinaryExpression) exp);
  78. case ExpressionType.TypeIs:
  79. return this.VisitTypeIs ((TypeBinaryExpression) exp);
  80. case ExpressionType.Conditional:
  81. return this.VisitConditional ((ConditionalExpression) exp);
  82. case ExpressionType.Constant:
  83. return this.VisitConstant ((ConstantExpression) exp);
  84. case ExpressionType.Parameter:
  85. return this.VisitParameter ((ParameterExpression) exp);
  86. case ExpressionType.MemberAccess:
  87. return this.VisitMemberAccess ((MemberExpression) exp);
  88. case ExpressionType.Call:
  89. return this.VisitMethodCall ((MethodCallExpression) exp);
  90. case ExpressionType.Lambda:
  91. return this.VisitLambda ((LambdaExpression) exp);
  92. case ExpressionType.New:
  93. return this.VisitNew ((NewExpression) exp);
  94. case ExpressionType.NewArrayInit:
  95. case ExpressionType.NewArrayBounds:
  96. return this.VisitNewArray ((NewArrayExpression) exp);
  97. case ExpressionType.Invoke:
  98. return this.VisitInvocation ((InvocationExpression) exp);
  99. case ExpressionType.MemberInit:
  100. return this.VisitMemberInit ((MemberInitExpression) exp);
  101. case ExpressionType.ListInit:
  102. return this.VisitListInit ((ListInitExpression) exp);
  103. default:
  104. throw new Exception (string.Format ("Unhandled expression type: '{0}'", exp.NodeType));
  105. }
  106. }
  107. protected virtual MemberBinding VisitBinding (MemberBinding binding)
  108. {
  109. switch (binding.BindingType) {
  110. case MemberBindingType.Assignment:
  111. return this.VisitMemberAssignment ((MemberAssignment) binding);
  112. case MemberBindingType.MemberBinding:
  113. return this.VisitMemberMemberBinding ((MemberMemberBinding) binding);
  114. case MemberBindingType.ListBinding:
  115. return this.VisitMemberListBinding ((MemberListBinding) binding);
  116. default:
  117. throw new Exception (string.Format ("Unhandled binding type '{0}'", binding.BindingType));
  118. }
  119. }
  120. protected virtual ElementInit VisitElementInitializer (ElementInit initializer)
  121. {
  122. ReadOnlyCollection<Expression> arguments = this.VisitExpressionList (initializer.Arguments);
  123. if (arguments != initializer.Arguments) return Expression.ElementInit (initializer.AddMethod, arguments);
  124. return initializer;
  125. }
  126. protected virtual Expression VisitUnary (UnaryExpression u)
  127. {
  128. Expression operand = this.Visit (u.Operand);
  129. if (operand != u.Operand) return Expression.MakeUnary (u.NodeType, operand, u.Type, u.Method);
  130. return u;
  131. }
  132. protected virtual Expression VisitBinary (BinaryExpression b)
  133. {
  134. Expression left = this.Visit (b.Left);
  135. Expression right = this.Visit (b.Right);
  136. Expression conversion = this.Visit (b.Conversion);
  137. if (left != b.Left || right != b.Right || conversion != b.Conversion) {
  138. if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) {
  139. return Expression.Coalesce (left, right, conversion as LambdaExpression);
  140. } else {
  141. return Expression.MakeBinary (b.NodeType, left, right, b.IsLiftedToNull, b.Method);
  142. }
  143. }
  144. return b;
  145. }
  146. protected virtual Expression VisitTypeIs (TypeBinaryExpression b)
  147. {
  148. Expression expr = this.Visit (b.Expression);
  149. if (expr != b.Expression) {
  150. return Expression.TypeIs (expr, b.TypeOperand);
  151. }
  152. return b;
  153. }
  154. protected virtual Expression VisitConstant (ConstantExpression c)
  155. {
  156. return c;
  157. }
  158. protected virtual Expression VisitConditional (ConditionalExpression c)
  159. {
  160. Expression test = this.Visit (c.Test);
  161. Expression ifTrue = this.Visit (c.IfTrue);
  162. Expression ifFalse = this.Visit (c.IfFalse);
  163. if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) {
  164. return Expression.Condition (test, ifTrue, ifFalse);
  165. }
  166. return c;
  167. }
  168. protected virtual Expression VisitParameter (ParameterExpression p)
  169. {
  170. return p;
  171. }
  172. protected virtual Expression VisitMemberAccess (MemberExpression m)
  173. {
  174. Expression exp = this.Visit (m.Expression);
  175. if (exp != m.Expression) {
  176. return Expression.MakeMemberAccess (exp, m.Member);
  177. }
  178. return m;
  179. }
  180. protected virtual Expression VisitMethodCall (MethodCallExpression m)
  181. {
  182. Expression obj = this.Visit (m.Object);
  183. IEnumerable<Expression> args = this.VisitExpressionList (m.Arguments);
  184. if (obj != m.Object || args != m.Arguments) {
  185. return Expression.Call (obj, m.Method, args);
  186. }
  187. return m;
  188. }
  189. protected virtual ReadOnlyCollection<Expression> VisitExpressionList (ReadOnlyCollection<Expression> original)
  190. {
  191. var list = VisitList (original, Visit);
  192. if (list == null) return original;
  193. return new ReadOnlyCollection<Expression> (list);
  194. }
  195. protected virtual MemberAssignment VisitMemberAssignment (MemberAssignment assignment)
  196. {
  197. Expression e = this.Visit (assignment.Expression);
  198. if (e != assignment.Expression) return Expression.Bind (assignment.Member, e);
  199. return assignment;
  200. }
  201. protected virtual MemberMemberBinding VisitMemberMemberBinding (MemberMemberBinding binding)
  202. {
  203. IEnumerable<MemberBinding> bindings = this.VisitBindingList (binding.Bindings);
  204. if (bindings != binding.Bindings) return Expression.MemberBind (binding.Member, bindings);
  205. return binding;
  206. }
  207. protected virtual MemberListBinding VisitMemberListBinding (MemberListBinding binding)
  208. {
  209. IEnumerable<ElementInit> initializers = this.VisitElementInitializerList (binding.Initializers);
  210. if (initializers != binding.Initializers) return Expression.ListBind (binding.Member, initializers);
  211. return binding;
  212. }
  213. protected virtual IEnumerable<MemberBinding> VisitBindingList (ReadOnlyCollection<MemberBinding> original)
  214. {
  215. return VisitList (original, VisitBinding);
  216. }
  217. protected virtual IEnumerable<ElementInit> VisitElementInitializerList (ReadOnlyCollection<ElementInit> original)
  218. {
  219. return VisitList (original, VisitElementInitializer);
  220. }
  221. private IList<TElement> VisitList<TElement> (ReadOnlyCollection<TElement> original, Func<TElement, TElement> visit)
  222. {
  223. List<TElement> list = null;
  224. for (int i = 0, n = original.Count; i < n; i++) {
  225. TElement element = visit (original [i]);
  226. if (list != null) {
  227. list.Add (element);
  228. } else if (!EqualityComparer<TElement>.Default.Equals (element, original [i])) {
  229. list = new List<TElement> (n);
  230. for (int j = 0; j < i; j++) {
  231. list.Add (original [j]);
  232. }
  233. list.Add (element);
  234. }
  235. }
  236. if (list != null)
  237. return list;
  238. return original;
  239. }
  240. protected virtual Expression VisitLambda (LambdaExpression lambda)
  241. {
  242. Expression body = this.Visit (lambda.Body);
  243. if (body != lambda.Body) return Expression.Lambda (lambda.Type, body, lambda.Parameters);
  244. return lambda;
  245. }
  246. protected virtual NewExpression VisitNew (NewExpression nex)
  247. {
  248. IEnumerable<Expression> args = this.VisitExpressionList (nex.Arguments);
  249. if (args != nex.Arguments) {
  250. if (nex.Members != null)
  251. return Expression.New (nex.Constructor, args, nex.Members);
  252. else
  253. return Expression.New (nex.Constructor, args);
  254. }
  255. return nex;
  256. }
  257. protected virtual Expression VisitMemberInit (MemberInitExpression init)
  258. {
  259. NewExpression n = this.VisitNew (init.NewExpression);
  260. IEnumerable<MemberBinding> bindings = this.VisitBindingList (init.Bindings);
  261. if (n != init.NewExpression || bindings != init.Bindings) return Expression.MemberInit (n, bindings);
  262. return init;
  263. }
  264. protected virtual Expression VisitListInit (ListInitExpression init)
  265. {
  266. NewExpression n = this.VisitNew (init.NewExpression);
  267. IEnumerable<ElementInit> initializers = this.VisitElementInitializerList (init.Initializers);
  268. if (n != init.NewExpression || initializers != init.Initializers) return Expression.ListInit (n, initializers);
  269. return init;
  270. }
  271. protected virtual Expression VisitNewArray (NewArrayExpression na)
  272. {
  273. IEnumerable<Expression> exprs = this.VisitExpressionList (na.Expressions);
  274. if (exprs != na.Expressions) {
  275. if (na.NodeType == ExpressionType.NewArrayInit) {
  276. return Expression.NewArrayInit (na.Type.GetElementType (), exprs);
  277. } else {
  278. return Expression.NewArrayBounds (na.Type.GetElementType (), exprs);
  279. }
  280. }
  281. return na;
  282. }
  283. protected virtual Expression VisitInvocation (InvocationExpression iv)
  284. {
  285. IEnumerable<Expression> args = this.VisitExpressionList (iv.Arguments);
  286. Expression expr = this.Visit (iv.Expression);
  287. if (args != iv.Arguments || expr != iv.Expression) return Expression.Invoke (expr, args);
  288. return iv;
  289. }
  290. }
  291. }