2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Core / System.Linq.Expressions / Expression.cs
blobb87a634af869c348171f203529453e1663fe8338
1 //
2 // Expression.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
7 //
8 // (C) 2008 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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.ObjectModel;
34 using System.Globalization;
35 using System.Linq;
36 using System.Reflection;
37 using System.Reflection.Emit;
39 namespace System.Linq.Expressions {
41 public abstract class Expression {
43 ExpressionType node_type;
44 Type type;
46 internal const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
47 internal const BindingFlags NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
48 internal const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
49 internal const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
50 internal const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
51 internal const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
53 public ExpressionType NodeType {
54 get { return node_type; }
57 public Type Type {
58 get { return type; }
61 protected Expression (ExpressionType node_type, Type type)
63 this.node_type = node_type;
64 this.type = type;
67 public override string ToString ()
69 return ExpressionPrinter.ToString (this);
72 #region Binary Expressions
74 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param)
76 return GetUnaryOperator (oper_name, declaring, param, null);
79 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param, Type ret)
81 var methods = declaring.GetNotNullableType ().GetMethods (PublicStatic);
83 foreach (var method in methods) {
84 if (method.Name != oper_name)
85 continue;
87 var parameters = method.GetParameters ();
88 if (parameters.Length != 1)
89 continue;
91 if (method.IsGenericMethod)
92 continue;
94 if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
95 continue;
97 if (ret != null && method.ReturnType != ret.GetNotNullableType ())
98 continue;
100 return method;
103 return null;
106 internal static MethodInfo GetTrueOperator (Type self)
108 return GetBooleanOperator ("op_True", self);
111 internal static MethodInfo GetFalseOperator (Type self)
113 return GetBooleanOperator ("op_False", self);
116 static MethodInfo GetBooleanOperator (string op, Type self)
118 return GetUnaryOperator (op, self, self, typeof (bool));
121 static bool IsAssignableToParameterType (Type type, ParameterInfo param)
123 var ptype = param.ParameterType;
124 if (ptype.IsByRef)
125 ptype = ptype.GetElementType ();
127 return type.GetNotNullableType ().IsAssignableTo (ptype);
130 static MethodInfo CheckUnaryMethod (MethodInfo method, Type param)
132 if (method.ReturnType == typeof (void))
133 throw new ArgumentException ("Specified method must return a value", "method");
135 if (!method.IsStatic)
136 throw new ArgumentException ("Method must be static", "method");
138 var parameters = method.GetParameters ();
140 if (parameters.Length != 1)
141 throw new ArgumentException ("Must have only one parameters", "method");
143 if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
144 throw new InvalidOperationException ("left-side argument type does not match expression type");
146 return method;
149 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method, Func<Type, bool> validator)
151 if (expression == null)
152 throw new ArgumentNullException ("expression");
154 if (method != null)
155 return CheckUnaryMethod (method, expression.Type);
157 var type = expression.Type.GetNotNullableType ();
159 if (validator (type))
160 return null;
162 if (oper_name != null) {
163 method = GetUnaryOperator (oper_name, type, expression.Type);
164 if (method != null)
165 return method;
168 throw new InvalidOperationException (
169 string.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
172 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
174 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
176 foreach (var method in methods) {
177 if (method.Name != oper_name)
178 continue;
180 var parameters = method.GetParameters ();
181 if (parameters.Length != 2)
182 continue;
184 if (method.IsGenericMethod)
185 continue;
187 if (!IsAssignableToParameterType (left.Type, parameters [0]))
188 continue;
190 if (!IsAssignableToParameterType (right.Type, parameters [1]))
191 continue;
193 // Method has papers in order.
194 return method;
197 return null;
201 // Performs basic checks on the incoming expressions for binary expressions
202 // and any provided MethodInfo.
204 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
206 if (left == null)
207 throw new ArgumentNullException ("left");
208 if (right == null)
209 throw new ArgumentNullException ("right");
211 if (method != null){
212 if (method.ReturnType == typeof (void))
213 throw new ArgumentException ("Specified method must return a value", "method");
215 if (!method.IsStatic)
216 throw new ArgumentException ("Method must be static", "method");
218 var parameters = method.GetParameters ();
220 if (parameters.Length != 2)
221 throw new ArgumentException ("Must have only two parameters", "method");
223 if (!IsAssignableToParameterType (left.Type, parameters [0]))
224 throw new InvalidOperationException ("left-side argument type does not match left expression type");
226 if (!IsAssignableToParameterType (right.Type, parameters [1]))
227 throw new InvalidOperationException ("right-side argument type does not match right expression type");
229 return method;
230 } else {
231 Type ltype = left.Type;
232 Type rtype = right.Type;
233 Type ultype = ltype.GetNotNullableType ();
234 Type urtype = rtype.GetNotNullableType ();
236 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
237 if (ultype == typeof (bool)) {
238 if (ultype == urtype && ltype == rtype)
239 return null;
243 // Use IsNumber to avoid expensive reflection.
244 if (IsNumber (ultype)) {
245 if (ultype == urtype && ltype == rtype)
246 return null;
248 if (oper_name != null){
249 method = GetBinaryOperator (oper_name, urtype, left, right);
250 if (method != null)
251 return method;
255 if (oper_name != null){
256 method = GetBinaryOperator (oper_name, ultype, left, right);
257 if (method != null)
258 return method;
261 if (oper_name == "op_Equality" || oper_name == "op_Inequality") {
263 // == and != allow reference types without operators defined.
265 if (!ltype.IsValueType && !rtype.IsValueType)
266 return null;
268 if (ltype == rtype && ultype.IsEnum)
269 return null;
271 if (ltype == rtype && ultype == typeof (bool))
272 return null;
275 if (oper_name == "op_LeftShift" || oper_name == "op_RightShift") {
276 if (IsInt (ultype) && urtype == typeof (int))
277 return null;
280 throw new InvalidOperationException (
281 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
286 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
287 // only ints and bools are allowed
289 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
291 if (left == null)
292 throw new ArgumentNullException ("left");
293 if (right == null)
294 throw new ArgumentNullException ("right");
296 if (method == null) {
297 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
298 if (left.Type == right.Type && IsIntOrBool (left.Type))
299 return null;
302 method = BinaryCoreCheck (oper_name, left, right, method);
303 if (method == null) {
304 // The check in BinaryCoreCheck allows a bit more than we do
305 // (floats and doubles). Catch this here
306 if (left.Type == typeof (double) || left.Type == typeof (float))
307 throw new InvalidOperationException ("Types not supported");
310 return method;
313 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
315 bool is_lifted;
316 Type type;
318 if (method == null) {
319 is_lifted = left.Type.IsNullable ();
320 type = left.Type;
321 } else {
322 var parameters = method.GetParameters ();
324 var lp = parameters [0];
325 var rp = parameters [1];
327 if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
328 is_lifted = false;
329 type = method.ReturnType;
330 } else if (left.Type.IsNullable ()
331 && right.Type.IsNullable ()
332 && left.Type.GetNotNullableType () == lp.ParameterType
333 && right.Type.GetNotNullableType () == rp.ParameterType
334 && !method.ReturnType.IsNullable ()) {
336 is_lifted = true;
337 type = method.ReturnType.MakeNullableType ();
338 } else
339 throw new InvalidOperationException ();
342 return new BinaryExpression (et, type, left, right, is_lifted, is_lifted, method, null);
345 static bool IsAssignableToOperatorParameter (Expression expression, ParameterInfo parameter)
347 if (expression.Type == parameter.ParameterType)
348 return true;
350 if ((!expression.Type.IsNullable () && !parameter.ParameterType.IsNullable ())
351 && IsAssignableToParameterType (expression.Type, parameter))
352 return true;
354 return false;
357 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
359 bool is_lifted;
360 Type type;
362 if (method == null) {
363 type = expression.Type;
364 is_lifted = type.IsNullable ();
365 } else {
366 var parameter = method.GetParameters () [0];
368 if (IsAssignableToOperatorParameter (expression, parameter)) {
369 is_lifted = false;
370 type = method.ReturnType;
371 } else if (expression.Type.IsNullable ()
372 && expression.Type.GetNotNullableType () == parameter.ParameterType
373 && !method.ReturnType.IsNullable ()) {
375 is_lifted = true;
376 type = method.ReturnType.MakeNullableType ();
377 } else
378 throw new InvalidOperationException ();
381 return new UnaryExpression (et, expression, type, method, is_lifted);
384 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
386 bool is_lifted;
387 Type type;
389 if (method == null) {
390 if (!left.Type.IsNullable () && !right.Type.IsNullable ()) {
391 is_lifted = false;
392 liftToNull = false;
393 type = typeof (bool);
394 } else if (left.Type.IsNullable () && right.Type.IsNullable ()) {
395 is_lifted = true;
396 type = liftToNull ? typeof (bool?) : typeof (bool);
397 } else
398 throw new InvalidOperationException ();
399 } else {
400 var parameters = method.GetParameters ();
402 var lp = parameters [0];
403 var rp = parameters [1];
405 if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
406 is_lifted = false;
407 liftToNull = false;
408 type = method.ReturnType;
409 } else if (left.Type.IsNullable ()
410 && right.Type.IsNullable ()
411 && left.Type.GetNotNullableType () == lp.ParameterType
412 && right.Type.GetNotNullableType () == rp.ParameterType) {
414 is_lifted = true;
416 if (method.ReturnType == typeof (bool))
417 type = liftToNull ? typeof (bool?) : typeof (bool);
418 else if (!method.ReturnType.IsNullable ()) {
420 // This behavior is not documented: what
421 // happens if the result is not typeof(bool), but
422 // the parameters are nullable: the result
423 // becomes nullable<returntype>
425 // See:
426 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
428 type = method.ReturnType.MakeNullableType ();
429 } else
430 throw new InvalidOperationException ();
431 } else
432 throw new InvalidOperationException ();
435 return new BinaryExpression (et, type, left, right, liftToNull, is_lifted, method, null);
439 // Arithmetic
441 public static BinaryExpression Add (Expression left, Expression right)
443 return Add (left, right, null);
446 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
448 method = BinaryCoreCheck ("op_Addition", left, right, method);
450 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
453 public static BinaryExpression AddChecked (Expression left, Expression right)
455 return AddChecked (left, right, null);
458 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
460 method = BinaryCoreCheck ("op_Addition", left, right, method);
462 // The check in BinaryCoreCheck allows a bit more than we do
463 // (byte, sbyte). Catch that here
464 if (method == null) {
465 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
466 throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
469 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
472 public static BinaryExpression Subtract (Expression left, Expression right)
474 return Subtract (left, right, null);
477 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
479 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
481 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
484 public static BinaryExpression SubtractChecked (Expression left, Expression right)
486 return SubtractChecked (left, right, null);
489 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
491 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
493 // The check in BinaryCoreCheck allows a bit more than we do
494 // (byte, sbyte). Catch that here
495 if (method == null) {
496 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
497 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
500 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
503 public static BinaryExpression Modulo (Expression left, Expression right)
505 return Modulo (left, right, null);
508 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
510 method = BinaryCoreCheck ("op_Modulus", left, right, method);
512 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
515 public static BinaryExpression Multiply (Expression left, Expression right)
517 return Multiply (left, right, null);
520 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
522 method = BinaryCoreCheck ("op_Multiply", left, right, method);
524 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
527 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
529 return MultiplyChecked (left, right, null);
532 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
534 method = BinaryCoreCheck ("op_Multiply", left, right, method);
536 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
539 public static BinaryExpression Divide (Expression left, Expression right)
541 return Divide (left, right, null);
544 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
546 method = BinaryCoreCheck ("op_Division", left, right, method);
548 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
551 public static BinaryExpression Power (Expression left, Expression right)
553 return Power (left, right, null);
556 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
558 method = BinaryCoreCheck (null, left, right, method);
560 if (left.Type.GetNotNullableType () != typeof (double))
561 throw new InvalidOperationException ("Power only supports double arguments");
563 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
567 // Bitwise
569 public static BinaryExpression And (Expression left, Expression right)
571 return And (left, right, null);
574 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
576 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
578 return MakeSimpleBinary (ExpressionType.And, left, right, method);
581 public static BinaryExpression Or (Expression left, Expression right)
583 return Or (left, right, null);
586 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
588 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
590 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
593 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
595 return ExclusiveOr (left, right, null);
598 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
600 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
602 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
605 public static BinaryExpression LeftShift (Expression left, Expression right)
607 return LeftShift (left, right, null);
610 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
612 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
614 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
617 public static BinaryExpression RightShift (Expression left, Expression right)
619 return RightShift (left, right, null);
622 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
624 method = BinaryCoreCheck ("op_RightShift", left, right, method);
626 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
630 // Short-circuit
632 public static BinaryExpression AndAlso (Expression left, Expression right)
634 return AndAlso (left, right, null);
637 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
639 method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
641 return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
644 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
646 method = BinaryCoreCheck (oper, left, right, method);
648 if (method == null) {
649 if (left.Type.GetNotNullableType () != typeof (bool))
650 throw new InvalidOperationException ("Only booleans are allowed");
651 } else {
652 var type = left.Type.GetNotNullableType ();
654 // The method should have identical parameter and return types.
655 if (left.Type != right.Type || method.ReturnType != type)
656 throw new ArgumentException ("left, right and return type must match");
658 var optrue = GetTrueOperator (type);
659 var opfalse = GetFalseOperator (type);
661 if (optrue == null || opfalse == null)
662 throw new ArgumentException ("Operators true and false are required but not defined");
665 return method;
668 public static BinaryExpression OrElse (Expression left, Expression right)
670 return OrElse (left, right, null);
673 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
675 method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
677 return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
681 // Comparison
683 public static BinaryExpression Equal (Expression left, Expression right)
685 return Equal (left, right, false, null);
688 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
690 method = BinaryCoreCheck ("op_Equality", left, right, method);
692 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
695 public static BinaryExpression NotEqual (Expression left, Expression right)
697 return NotEqual (left, right, false, null);
701 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
703 method = BinaryCoreCheck ("op_Inequality", left, right, method);
705 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
708 public static BinaryExpression GreaterThan (Expression left, Expression right)
710 return GreaterThan (left, right, false, null);
713 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
715 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
717 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
720 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
722 return GreaterThanOrEqual (left, right, false, null);
726 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
728 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
730 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
733 public static BinaryExpression LessThan (Expression left, Expression right)
735 return LessThan (left, right, false, null);
738 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
740 method = BinaryCoreCheck ("op_LessThan", left, right, method);
742 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
745 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
747 return LessThanOrEqual (left, right, false, null);
750 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
752 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
754 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
758 // Miscelaneous
761 static void CheckArray (Expression array)
763 if (array == null)
764 throw new ArgumentNullException ("array");
765 if (!array.Type.IsArray)
766 throw new ArgumentException ("The array argument must be of type array");
769 public static BinaryExpression ArrayIndex (Expression array, Expression index)
771 CheckArray (array);
773 if (index == null)
774 throw new ArgumentNullException ("index");
775 if (array.Type.GetArrayRank () != 1)
776 throw new ArgumentException ("The array argument must be a single dimensional array");
777 if (index.Type != typeof (int))
778 throw new ArgumentException ("The index must be of type int");
780 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
783 public static BinaryExpression Coalesce (Expression left, Expression right)
785 return Coalesce (left, right, null);
788 static BinaryExpression MakeCoalesce (Expression left, Expression right)
790 Type result = null;
792 if (left.Type.IsNullable ()) {
793 Type lbase = left.Type.GetNotNullableType ();
795 if (!right.Type.IsNullable () && right.Type.IsAssignableTo (lbase))
796 result = lbase;
799 if (result == null && right.Type.IsAssignableTo (left.Type))
800 result = left.Type;
802 if (result == null) {
803 if (left.Type.IsNullable () && left.Type.GetNotNullableType ().IsAssignableTo (right.Type))
804 result = right.Type;
807 if (result == null)
808 throw new ArgumentException ("Incompatible argument types");
810 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, null);
813 static BinaryExpression MakeConvertedCoalesce (Expression left, Expression right, LambdaExpression conversion)
815 var invoke = conversion.Type.GetInvokeMethod ();
817 CheckNotVoid (invoke.ReturnType);
819 if (invoke.ReturnType != right.Type)
820 throw new InvalidOperationException ("Conversion return type doesn't march right type");
822 var parameters = invoke.GetParameters ();
824 if (parameters.Length != 1)
825 throw new ArgumentException ("Conversion has wrong number of parameters");
827 if (!IsAssignableToParameterType (left.Type, parameters [0]))
828 throw new InvalidOperationException ("Conversion argument doesn't marcht left type");
830 return new BinaryExpression (ExpressionType.Coalesce, right.Type, left, right, false, false, null, conversion);
833 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
835 if (left == null)
836 throw new ArgumentNullException ("left");
837 if (right == null)
838 throw new ArgumentNullException ("right");
841 // First arg must ne nullable (either Nullable<T> or a reference type
843 if (left.Type.IsValueType && !left.Type.IsNullable ())
844 throw new InvalidOperationException ("Left expression can never be null");
846 if (conversion != null)
847 return MakeConvertedCoalesce (left, right, conversion);
849 return MakeCoalesce (left, right);
853 // MakeBinary constructors
855 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
857 return MakeBinary (binaryType, left, right, false, null);
860 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
862 return MakeBinary (binaryType, left, right, liftToNull, method, null);
865 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
867 switch (binaryType) {
868 case ExpressionType.Add:
869 return Add (left, right, method);
870 case ExpressionType.AddChecked:
871 return AddChecked (left, right, method);
872 case ExpressionType.AndAlso:
873 return AndAlso (left, right);
874 case ExpressionType.Coalesce:
875 return Coalesce (left, right, conversion);
876 case ExpressionType.Divide:
877 return Divide (left, right, method);
878 case ExpressionType.Equal:
879 return Equal (left, right, liftToNull, method);
880 case ExpressionType.ExclusiveOr:
881 return ExclusiveOr (left, right, method);
882 case ExpressionType.GreaterThan:
883 return GreaterThan (left, right, liftToNull, method);
884 case ExpressionType.GreaterThanOrEqual:
885 return GreaterThanOrEqual (left, right, liftToNull, method);
886 case ExpressionType.LeftShift:
887 return LeftShift (left, right, method);
888 case ExpressionType.LessThan:
889 return LessThan (left, right, liftToNull, method);
890 case ExpressionType.LessThanOrEqual:
891 return LessThanOrEqual (left, right, liftToNull, method);
892 case ExpressionType.Modulo:
893 return Modulo (left, right, method);
894 case ExpressionType.Multiply:
895 return Multiply (left, right, method);
896 case ExpressionType.MultiplyChecked:
897 return MultiplyChecked (left, right, method);
898 case ExpressionType.NotEqual:
899 return NotEqual (left, right, liftToNull, method);
900 case ExpressionType.OrElse:
901 return OrElse (left, right);
902 case ExpressionType.Power:
903 return Power (left, right, method);
904 case ExpressionType.RightShift:
905 return RightShift (left, right, method);
906 case ExpressionType.Subtract:
907 return Subtract (left, right, method);
908 case ExpressionType.SubtractChecked:
909 return SubtractChecked (left, right, method);
910 case ExpressionType.And:
911 return And (left, right, method);
912 case ExpressionType.Or:
913 return Or (left, right, method);
916 throw new ArgumentException ("MakeBinary expect a binary node type");
919 #endregion
921 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
923 return ArrayIndex (array, indexes as IEnumerable<Expression>);
926 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
928 CheckArray (array);
930 if (indexes == null)
931 throw new ArgumentNullException ("indexes");
933 var args = indexes.ToReadOnlyCollection ();
934 if (array.Type.GetArrayRank () != args.Count)
935 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
937 foreach (var arg in args)
938 if (arg.Type != typeof (int))
939 throw new ArgumentException ("The index must be of type int");
941 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
944 public static UnaryExpression ArrayLength (Expression array)
946 if (array == null)
947 throw new ArgumentNullException ("array");
948 if (!array.Type.IsArray)
949 throw new ArgumentException ("The type of the expression must me Array");
950 if (array.Type.GetArrayRank () != 1)
951 throw new ArgumentException ("The array must be a single dimensional array");
953 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
956 public static MemberAssignment Bind (MemberInfo member, Expression expression)
958 if (member == null)
959 throw new ArgumentNullException ("member");
960 if (expression == null)
961 throw new ArgumentNullException ("expression");
963 Type type = null;
965 var prop = member as PropertyInfo;
966 if (prop != null && prop.GetSetMethod (true) != null)
967 type = prop.PropertyType;
969 var field = member as FieldInfo;
970 if (field != null)
971 type = field.FieldType;
973 if (type == null)
974 throw new ArgumentException ("member");
976 if (!expression.Type.IsAssignableTo (type))
977 throw new ArgumentException ("member");
979 return new MemberAssignment (member, expression);
982 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
984 if (propertyAccessor == null)
985 throw new ArgumentNullException ("propertyAccessor");
986 if (expression == null)
987 throw new ArgumentNullException ("expression");
989 CheckNonGenericMethod (propertyAccessor);
991 var prop = GetAssociatedProperty (propertyAccessor);
992 if (prop == null)
993 throw new ArgumentException ("propertyAccessor");
995 var setter = prop.GetSetMethod (true);
996 if (setter == null)
997 throw new ArgumentException ("setter");
999 if (!expression.Type.IsAssignableTo (prop.PropertyType))
1000 throw new ArgumentException ("member");
1002 return new MemberAssignment (prop, expression);
1005 public static MethodCallExpression Call (Expression instance, MethodInfo method)
1007 return Call (instance, method, null as IEnumerable<Expression>);
1010 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
1012 return Call (null, method, arguments as IEnumerable<Expression>);
1015 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
1017 return Call (instance, method, arguments as IEnumerable<Expression>);
1020 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
1022 if (method == null)
1023 throw new ArgumentNullException ("method");
1024 if (instance == null && !method.IsStatic)
1025 throw new ArgumentNullException ("instance");
1026 if (method.IsStatic && instance != null)
1027 throw new ArgumentException ("instance");
1028 if (!method.IsStatic && !instance.Type.IsAssignableTo (method.DeclaringType))
1029 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
1031 var args = CheckMethodArguments (method, arguments);
1033 return new MethodCallExpression (instance, method, args);
1036 static Type [] CollectTypes (IEnumerable<Expression> expressions)
1038 return (from arg in expressions select arg.Type).ToArray ();
1041 static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
1043 if (method == null)
1044 return null;
1046 if (!method.IsGenericMethod && (args == null || args.Length == 0))
1047 return method;
1049 if (args.Length == method.GetGenericArguments ().Length)
1050 return method.MakeGenericMethod (args);
1052 return null;
1055 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
1057 if (instance == null)
1058 throw new ArgumentNullException ("instance");
1059 if (methodName == null)
1060 throw new ArgumentNullException ("methodName");
1062 var method = TryGetMethod (instance.Type, methodName, AllInstance,
1063 CollectTypes (arguments), typeArguments);
1065 var args = CheckMethodArguments (method, arguments);
1067 return new MethodCallExpression (instance, method, args);
1070 static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes, Type [] argumentTypes)
1072 if (method.Name != name)
1073 return false;
1075 var parameters = method.GetParameters ();
1077 if (parameters.Length != parameterTypes.Length)
1078 return false;
1080 if (method.IsGenericMethod && method.IsGenericMethodDefinition) {
1081 var closed = TryMakeGeneric (method, argumentTypes);
1082 if (closed == null)
1083 return false;
1085 return MethodMatch (closed, name, parameterTypes, argumentTypes);
1086 } else if (!method.IsGenericMethod && (argumentTypes != null && argumentTypes.Length > 0))
1087 return false;
1089 for (int i = 0; i < parameters.Length; i++) {
1090 var type = parameterTypes [i];
1091 var parameter = parameters [i];
1092 if (!IsAssignableToParameterType (type, parameter)
1093 && !IsExpressionOfParameter (type, parameter.ParameterType))
1094 return false;
1097 return true;
1100 static bool IsExpressionOfParameter (Type type, Type ptype)
1102 return ptype.IsGenericInstanceOf (typeof (Expression<>)) && ptype.GetFirstGenericArgument () == type;
1105 static MethodInfo TryGetMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
1107 var methods = from meth in type.GetMethods (flags)
1108 where MethodMatch (meth, methodName, parameterTypes, argumentTypes)
1109 select meth;
1111 if (methods.Count () > 1)
1112 throw new InvalidOperationException ("Too many method candidates");
1114 var method = TryMakeGeneric (methods.FirstOrDefault (), argumentTypes);
1115 if (method != null)
1116 return method;
1118 throw new InvalidOperationException ("No such method");
1121 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
1123 if (type == null)
1124 throw new ArgumentNullException ("type");
1125 if (methodName == null)
1126 throw new ArgumentNullException ("methodName");
1128 var method = TryGetMethod (type, methodName, AllStatic,
1129 CollectTypes (arguments), typeArguments);
1131 var args = CheckMethodArguments (method, arguments);
1133 return new MethodCallExpression (method, args);
1136 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
1138 if (test == null)
1139 throw new ArgumentNullException ("test");
1140 if (ifTrue == null)
1141 throw new ArgumentNullException ("ifTrue");
1142 if (ifFalse == null)
1143 throw new ArgumentNullException ("ifFalse");
1144 if (test.Type != typeof (bool))
1145 throw new ArgumentException ("Test expression should be of type bool");
1146 if (ifTrue.Type != ifFalse.Type)
1147 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1149 return new ConditionalExpression (test, ifTrue, ifFalse);
1152 public static ConstantExpression Constant (object value)
1154 if (value == null)
1155 return new ConstantExpression (null, typeof (object));
1157 return Constant (value, value.GetType ());
1160 public static ConstantExpression Constant (object value, Type type)
1162 if (type == null)
1163 throw new ArgumentNullException ("type");
1166 // value must be compatible with type, no conversions
1167 // are allowed
1169 if (value == null){
1170 if (type.IsValueType && !type.IsNullable ())
1171 throw new ArgumentException ();
1172 } else {
1173 if (!(type.IsValueType && type.IsNullable ()) && !value.GetType ().IsAssignableTo (type))
1174 throw new ArgumentException ();
1178 return new ConstantExpression (value, type);
1181 static bool IsConvertiblePrimitive (Type type)
1183 var t = type.GetNotNullableType ();
1185 if (t == typeof (bool))
1186 return false;
1188 if (t.IsEnum)
1189 return true;
1191 return t.IsPrimitive;
1194 internal static bool IsPrimitiveConversion (Type type, Type target)
1196 if (type == target)
1197 return true;
1199 if (type.IsNullable () && target == type.GetNotNullableType ())
1200 return true;
1202 if (target.IsNullable () && type == target.GetNotNullableType ())
1203 return true;
1205 if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
1206 return true;
1208 return false;
1211 internal static bool IsReferenceConversion (Type type, Type target)
1213 if (type == target)
1214 return true;
1216 if (type == typeof (object) || target == typeof (object))
1217 return true;
1219 if (type.IsInterface || target.IsInterface)
1220 return true;
1222 if (type.IsValueType || target.IsValueType)
1223 return false;
1225 if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
1226 return true;
1228 return false;
1231 public static UnaryExpression Convert (Expression expression, Type type)
1233 return Convert (expression, type, null);
1236 static MethodInfo GetUserConversionMethod (Type type, Type target)
1238 var method = GetUnaryOperator ("op_Explicit", type, type, target);
1239 if (method == null)
1240 method = GetUnaryOperator ("op_Implicit", type, type, target);
1241 if (method == null)
1242 method = GetUnaryOperator ("op_Explicit", target, type, target);
1243 if (method == null)
1244 method = GetUnaryOperator ("op_Implicit", target, type, target);
1245 if (method == null)
1246 throw new InvalidOperationException ();
1248 return method;
1251 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1253 if (expression == null)
1254 throw new ArgumentNullException ("expression");
1255 if (type == null)
1256 throw new ArgumentNullException ("type");
1258 var et = expression.Type;
1260 if (method != null)
1261 CheckUnaryMethod (method, et);
1262 else if (!IsPrimitiveConversion (et, type) && !IsReferenceConversion (et, type))
1263 method = GetUserConversionMethod (et, type);
1265 return new UnaryExpression (ExpressionType.Convert,
1266 expression, type, method,
1267 IsConvertNodeLifted (method, expression, type));
1270 static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
1272 if (method == null)
1273 return operand.Type.IsNullable () || target.IsNullable ();
1275 if (operand.Type.IsNullable () && !ParameterMatch (method, operand.Type))
1276 return true;
1278 if (target.IsNullable () && !ReturnTypeMatch (method, target))
1279 return true;
1281 return false;
1284 static bool ParameterMatch (MethodInfo method, Type type)
1286 return method.GetParameters () [0].ParameterType == type;
1289 static bool ReturnTypeMatch (MethodInfo method, Type type)
1291 return method.ReturnType == type;
1294 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1296 return ConvertChecked (expression, type, null);
1299 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1301 if (expression == null)
1302 throw new ArgumentNullException ("expression");
1303 if (type == null)
1304 throw new ArgumentNullException ("type");
1306 var et = expression.Type;
1308 if (method != null)
1309 CheckUnaryMethod (method, et);
1310 else if (IsReferenceConversion (et, type))
1311 return Convert (expression, type, method);
1312 else if (!IsPrimitiveConversion (et, type))
1313 method = GetUserConversionMethod (et, type);
1315 return new UnaryExpression (ExpressionType.ConvertChecked,
1316 expression, type, method,
1317 IsConvertNodeLifted (method, expression, type));
1320 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1322 return ElementInit (addMethod, arguments as IEnumerable<Expression>);
1325 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1327 if (addMethod == null)
1328 throw new ArgumentNullException ("addMethod");
1329 if (arguments == null)
1330 throw new ArgumentNullException ("arguments");
1331 if (addMethod.Name.ToLower (CultureInfo.InvariantCulture) != "add")
1332 throw new ArgumentException ("addMethod");
1333 if (addMethod.IsStatic)
1334 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1336 var args = CheckMethodArguments (addMethod, arguments);
1338 return new ElementInit (addMethod, args);
1341 public static MemberExpression Field (Expression expression, FieldInfo field)
1343 if (field == null)
1344 throw new ArgumentNullException ("field");
1345 if (!field.IsStatic) {
1346 if (expression == null)
1347 throw new ArgumentNullException ("expression");
1348 if (!expression.Type.IsAssignableTo (field.DeclaringType))
1349 throw new ArgumentException ("field");
1350 } else if (expression != null)
1351 throw new ArgumentException ("expression");
1353 return new MemberExpression (expression, field, field.FieldType);
1356 public static MemberExpression Field (Expression expression, string fieldName)
1358 if (expression == null)
1359 throw new ArgumentNullException ("expression");
1361 var field = expression.Type.GetField (fieldName, AllInstance);
1362 if (field == null)
1363 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1365 return new MemberExpression (expression, field, field.FieldType);
1368 public static Type GetActionType (params Type [] typeArgs)
1370 if (typeArgs == null)
1371 throw new ArgumentNullException ("typeArgs");
1373 if (typeArgs.Length > 4)
1374 throw new ArgumentException ("No Action type of this arity");
1376 if (typeArgs.Length == 0)
1377 return typeof (Action);
1379 Type action = null;
1380 switch (typeArgs.Length) {
1381 case 1:
1382 action = typeof (Action<>);
1383 break;
1384 case 2:
1385 action = typeof (Action<,>);
1386 break;
1387 case 3:
1388 action = typeof (Action<,,>);
1389 break;
1390 case 4:
1391 action = typeof (Action<,,,>);
1392 break;
1395 return action.MakeGenericType (typeArgs);
1398 public static Type GetFuncType (params Type [] typeArgs)
1400 if (typeArgs == null)
1401 throw new ArgumentNullException ("typeArgs");
1403 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1404 throw new ArgumentException ("No Func type of this arity");
1406 Type func = null;
1407 switch (typeArgs.Length) {
1408 case 1:
1409 func = typeof (Func<>);
1410 break;
1411 case 2:
1412 func = typeof (Func<,>);
1413 break;
1414 case 3:
1415 func = typeof (Func<,,>);
1416 break;
1417 case 4:
1418 func = typeof (Func<,,,>);
1419 break;
1420 case 5:
1421 func = typeof (Func<,,,,>);
1422 break;
1425 return func.MakeGenericType (typeArgs);
1428 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1430 return Invoke (expression, arguments as IEnumerable<Expression>);
1433 static Type GetInvokableType (Type t)
1435 if (t.IsAssignableTo (typeof (Delegate)))
1436 return t;
1438 return GetGenericType (t, typeof (Expression<>));
1441 static Type GetGenericType (Type t, Type def)
1443 if (t == null)
1444 return null;
1446 if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
1447 return t;
1449 return GetGenericType (t.BaseType, def);
1452 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1454 if (expression == null)
1455 throw new ArgumentNullException ("expression");
1457 var type = GetInvokableType (expression.Type);
1458 if (type == null)
1459 throw new ArgumentException ("The type of the expression is not invokable");
1461 var args = arguments.ToReadOnlyCollection ();
1462 CheckForNull (args, "arguments");
1464 var invoke = type.GetInvokeMethod ();
1465 if (invoke == null)
1466 throw new ArgumentException ("expression");
1468 if (invoke.GetParameters ().Length != args.Count)
1469 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1471 args = CheckMethodArguments (invoke, args);
1473 return new InvocationExpression (expression, invoke.ReturnType, args);
1476 static bool CanAssign (Type target, Type source)
1478 // This catches object and value type mixage, type compatibility is handled later
1479 if (target.IsValueType ^ source.IsValueType)
1480 return false;
1482 return source.IsAssignableTo (target);
1485 static Expression CheckLambda (Type delegateType, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1487 if (!delegateType.IsSubclassOf (typeof (System.Delegate)))
1488 throw new ArgumentException ("delegateType");
1490 var invoke = delegateType.GetInvokeMethod ();
1491 if (invoke == null)
1492 throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
1494 var invoke_parameters = invoke.GetParameters ();
1495 if (invoke_parameters.Length != parameters.Count)
1496 throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType), "delegateType");
1498 for (int i = 0; i < invoke_parameters.Length; i++) {
1499 var parameter = parameters [i];
1500 if (parameter == null)
1501 throw new ArgumentNullException ("parameters");
1503 if (!CanAssign (parameter.Type, invoke_parameters [i].ParameterType))
1504 throw new ArgumentException (String.Format ("Can not assign a {0} to a {1}", invoke_parameters [i].ParameterType, parameter.Type));
1507 if (invoke.ReturnType != typeof (void)) {
1508 if (!CanAssign (invoke.ReturnType, body.Type)) {
1509 if (invoke.ReturnType.IsExpression ())
1510 return Expression.Quote (body);
1512 throw new ArgumentException (String.Format ("body type {0} can not be assigned to {1}", body.Type, invoke.ReturnType));
1515 return body;
1518 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1520 return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1523 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1525 if (body == null)
1526 throw new ArgumentNullException ("body");
1528 var ps = parameters.ToReadOnlyCollection ();
1530 body = CheckLambda (typeof (TDelegate), body, ps);
1532 return new Expression<TDelegate> (body, ps);
1535 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1537 if (body == null)
1538 throw new ArgumentNullException ("body");
1539 if (parameters.Length > 4)
1540 throw new ArgumentException ("Too many parameters");
1542 return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1545 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1547 if (parameters == null)
1548 parameters = new ParameterExpression [0];
1550 if (return_type == typeof (void))
1551 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1553 var types = new Type [parameters.Length + 1];
1554 for (int i = 0; i < types.Length - 1; i++)
1555 types [i] = parameters [i].Type;
1557 types [types.Length - 1] = return_type;
1558 return GetFuncType (types);
1561 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1563 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1566 static LambdaExpression CreateExpressionOf (Type type, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1568 return (LambdaExpression) typeof (Expression<>).MakeGenericType (type).GetConstructor (
1569 NonPublicInstance, null, new [] { typeof (Expression), typeof (ReadOnlyCollection<ParameterExpression>) }, null).Invoke (new object [] { body, parameters } );
1572 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1574 if (delegateType == null)
1575 throw new ArgumentNullException ("delegateType");
1576 if (body == null)
1577 throw new ArgumentNullException ("body");
1579 var ps = parameters.ToReadOnlyCollection ();
1581 body = CheckLambda (delegateType, body, ps);
1583 return CreateExpressionOf (delegateType, body, ps);
1586 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1588 return ListBind (member, initializers as IEnumerable<ElementInit>);
1591 static void CheckIsAssignableToIEnumerable (Type t)
1593 if (!t.IsAssignableTo (typeof (IEnumerable)))
1594 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
1597 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1599 if (member == null)
1600 throw new ArgumentNullException ("member");
1601 if (initializers == null)
1602 throw new ArgumentNullException ("initializers");
1604 var inits = initializers.ToReadOnlyCollection ();
1605 CheckForNull (inits, "initializers");
1607 member.OnFieldOrProperty (
1608 field => CheckIsAssignableToIEnumerable (field.FieldType),
1609 prop => CheckIsAssignableToIEnumerable (prop.PropertyType));
1611 return new MemberListBinding (member, inits);
1614 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1616 return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
1619 static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
1621 foreach (var t in collection)
1622 if (t == null)
1623 throw new ArgumentNullException (name);
1626 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1628 if (propertyAccessor == null)
1629 throw new ArgumentNullException ("propertyAccessor");
1630 if (initializers == null)
1631 throw new ArgumentNullException ("initializers");
1633 var inits = initializers.ToReadOnlyCollection ();
1634 CheckForNull (inits, "initializers");
1636 var prop = GetAssociatedProperty (propertyAccessor);
1637 if (prop == null)
1638 throw new ArgumentException ("propertyAccessor");
1640 CheckIsAssignableToIEnumerable (prop.PropertyType);
1642 return new MemberListBinding (prop, inits);
1645 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1647 return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
1650 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1652 var inits = CheckListInit (newExpression, initializers);
1654 return new ListInitExpression (newExpression, inits);
1657 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1659 return ListInit (newExpression, initializers as IEnumerable<Expression>);
1662 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1664 var inits = CheckListInit (newExpression, initializers);
1666 var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
1667 if (add_method == null)
1668 throw new InvalidOperationException ("No suitable add method found");
1670 return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
1673 static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
1675 return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
1678 static MethodInfo GetAddMethod (Type type, Type arg)
1680 return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
1683 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1685 return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
1688 static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
1690 if (newExpression == null)
1691 throw new ArgumentNullException ("newExpression");
1692 if (initializers == null)
1693 throw new ArgumentNullException ("initializers");
1694 if (!newExpression.Type.IsAssignableTo (typeof (IEnumerable)))
1695 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1697 var inits = initializers.ToReadOnlyCollection ();
1698 if (inits.Count == 0)
1699 throw new ArgumentException ("Empty initializers");
1701 CheckForNull (inits, "initializers");
1703 return inits;
1706 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1708 var inits = CheckListInit (newExpression, initializers);
1710 if (addMethod != null) {
1711 if (addMethod.Name.ToLower (CultureInfo.InvariantCulture) != "add")
1712 throw new ArgumentException ("addMethod");
1714 var parameters = addMethod.GetParameters ();
1715 if (parameters.Length != 1)
1716 throw new ArgumentException ("addMethod");
1718 foreach (var expression in inits)
1719 if (!IsAssignableToParameterType (expression.Type, parameters [0]))
1720 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1723 if (addMethod == null)
1724 addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
1726 if (addMethod == null)
1727 throw new InvalidOperationException ("No suitable add method found");
1729 return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
1732 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1734 if (expression == null)
1735 throw new ArgumentNullException ("expression");
1736 if (member == null)
1737 throw new ArgumentNullException ("member");
1739 var field = member as FieldInfo;
1740 if (field != null)
1741 return Field (expression, field);
1743 var property = member as PropertyInfo;
1744 if (property != null)
1745 return Property (expression, property);
1747 throw new ArgumentException ("Member should either be a field or a property");
1750 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1752 return MakeUnary (unaryType, operand, type, null);
1755 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1757 switch (unaryType) {
1758 case ExpressionType.ArrayLength:
1759 return ArrayLength (operand);
1760 case ExpressionType.Convert:
1761 return Convert (operand, type, method);
1762 case ExpressionType.ConvertChecked:
1763 return ConvertChecked (operand, type, method);
1764 case ExpressionType.Negate:
1765 return Negate (operand, method);
1766 case ExpressionType.NegateChecked:
1767 return NegateChecked (operand, method);
1768 case ExpressionType.Not:
1769 return Not (operand, method);
1770 case ExpressionType.Quote:
1771 return Quote (operand);
1772 case ExpressionType.TypeAs:
1773 return TypeAs (operand, type);
1774 case ExpressionType.UnaryPlus:
1775 return UnaryPlus (operand, method);
1778 throw new ArgumentException ("MakeUnary expect an unary operator");
1781 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
1783 return MemberBind (member, bindings as IEnumerable<MemberBinding>);
1786 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
1788 if (member == null)
1789 throw new ArgumentNullException ("member");
1791 var type = member.OnFieldOrProperty (
1792 field => field.FieldType,
1793 prop => prop.PropertyType);
1795 return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
1798 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
1800 return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
1803 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
1805 if (propertyAccessor == null)
1806 throw new ArgumentNullException ("propertyAccessor");
1808 var bds = bindings.ToReadOnlyCollection ();
1809 CheckForNull (bds, "bindings");
1811 var prop = GetAssociatedProperty (propertyAccessor);
1812 if (prop == null)
1813 throw new ArgumentException ("propertyAccessor");
1815 return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
1818 static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
1820 if (bindings == null)
1821 throw new ArgumentNullException ("bindings");
1823 var bds = bindings.ToReadOnlyCollection ();
1824 CheckForNull (bds, "bindings");
1826 foreach (var binding in bds)
1827 if (!type.IsAssignableTo (binding.Member.DeclaringType))
1828 throw new ArgumentException ("Type not assignable to member type");
1830 return bds;
1833 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
1835 return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
1838 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
1840 if (newExpression == null)
1841 throw new ArgumentNullException ("newExpression");
1843 return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
1846 public static UnaryExpression Negate (Expression expression)
1848 return Negate (expression, null);
1851 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1853 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1855 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1858 public static UnaryExpression NegateChecked (Expression expression)
1860 return NegateChecked (expression, null);
1863 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1865 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1867 return MakeSimpleUnary (ExpressionType.NegateChecked, expression, method);
1870 public static NewExpression New (ConstructorInfo constructor)
1872 if (constructor == null)
1873 throw new ArgumentNullException ("constructor");
1875 if (constructor.GetParameters ().Length > 0)
1876 throw new ArgumentException ("Constructor must be parameter less");
1878 return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
1881 public static NewExpression New (Type type)
1883 if (type == null)
1884 throw new ArgumentNullException ("type");
1886 CheckNotVoid (type);
1888 var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
1890 if (type.IsValueType)
1891 return new NewExpression (type, args);
1893 var ctor = type.GetConstructor (Type.EmptyTypes);
1894 if (ctor == null)
1895 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1897 return new NewExpression (ctor, args, null);
1900 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1902 return New (constructor, arguments as IEnumerable<Expression>);
1905 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1907 if (constructor == null)
1908 throw new ArgumentNullException ("constructor");
1910 var args = CheckMethodArguments (constructor, arguments);
1912 return new NewExpression (constructor, args, null);
1915 static IList<Expression> CreateArgumentList (IEnumerable<Expression> arguments)
1917 if (arguments == null)
1918 return arguments.ToReadOnlyCollection ();
1920 return arguments.ToList ();
1923 static void CheckNonGenericMethod (MethodBase method)
1925 if (method.IsGenericMethodDefinition || method.ContainsGenericParameters)
1926 throw new ArgumentException ("Can not used open generic methods");
1929 static ReadOnlyCollection<Expression> CheckMethodArguments (MethodBase method, IEnumerable<Expression> args)
1931 CheckNonGenericMethod (method);
1933 var arguments = CreateArgumentList (args);
1934 var parameters = method.GetParameters ();
1936 if (arguments.Count != parameters.Length)
1937 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1939 for (int i = 0; i < parameters.Length; i++) {
1940 if (arguments [i] == null)
1941 throw new ArgumentNullException ("arguments");
1943 if (!IsAssignableToParameterType (arguments [i].Type, parameters [i])) {
1944 if (!parameters [i].ParameterType.IsExpression ())
1945 throw new ArgumentException ("arguments");
1947 arguments [i] = Expression.Quote (arguments [i]);
1951 return arguments.ToReadOnlyCollection ();
1954 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1956 return New (constructor, arguments, members as IEnumerable<MemberInfo>);
1959 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1961 if (constructor == null)
1962 throw new ArgumentNullException ("constructor");
1964 var args = arguments.ToReadOnlyCollection ();
1965 var mmbs = members.ToReadOnlyCollection ();
1967 CheckForNull (args, "arguments");
1968 CheckForNull (mmbs, "members");
1970 args = CheckMethodArguments (constructor, arguments);
1972 if (args.Count != mmbs.Count)
1973 throw new ArgumentException ("Arguments count does not match members count");
1975 for (int i = 0; i < mmbs.Count; i++) {
1976 var member = mmbs [i];
1977 Type type = null;
1978 switch (member.MemberType) {
1979 case MemberTypes.Field:
1980 type = (member as FieldInfo).FieldType;
1981 break;
1982 case MemberTypes.Method:
1983 type = (member as MethodInfo).ReturnType;
1984 break;
1985 case MemberTypes.Property:
1986 var prop = member as PropertyInfo;
1987 if (prop.GetGetMethod (true) == null)
1988 throw new ArgumentException ("Property must have a getter");
1990 type = (member as PropertyInfo).PropertyType;
1991 break;
1992 default:
1993 throw new ArgumentException ("Member type not allowed");
1996 if (!args [i].Type.IsAssignableTo (type))
1997 throw new ArgumentException ("Argument type not assignable to member type");
2000 return new NewExpression (constructor, args, mmbs);
2003 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
2005 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
2008 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
2010 if (type == null)
2011 throw new ArgumentNullException ("type");
2012 if (bounds == null)
2013 throw new ArgumentNullException ("bounds");
2015 CheckNotVoid (type);
2017 var array_bounds = bounds.ToReadOnlyCollection ();
2018 foreach (var expression in array_bounds)
2019 if (!IsInt (expression.Type))
2020 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
2022 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
2025 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
2027 return NewArrayInit (type, initializers as IEnumerable<Expression>);
2030 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
2032 if (type == null)
2033 throw new ArgumentNullException ("type");
2034 if (initializers == null)
2035 throw new ArgumentNullException ("initializers");
2037 CheckNotVoid (type);
2039 var inits = initializers.ToReadOnlyCollection ();
2041 foreach (var expression in inits) {
2042 if (expression == null)
2043 throw new ArgumentNullException ("initializers");
2045 if (!expression.Type.IsAssignableTo (type))
2046 throw new InvalidOperationException (
2047 string.Format ("{0} IsAssignableTo {1}, expression [ {2} ] : {3}", expression.Type, type, expression.NodeType, expression));
2049 // TODO: Quote elements if type == typeof (Expression)
2052 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), inits);
2055 public static UnaryExpression Not (Expression expression)
2057 return Not (expression, null);
2060 public static UnaryExpression Not (Expression expression, MethodInfo method)
2062 Func<Type, bool> validator = type => IsIntOrBool (type);
2064 method = UnaryCoreCheck ("op_LogicalNot", expression, method, validator);
2066 if (method == null)
2067 method = UnaryCoreCheck ("op_OnesComplement", expression, method, validator);
2069 return MakeSimpleUnary (ExpressionType.Not, expression, method);
2072 static void CheckNotVoid (Type type)
2074 if (type == typeof (void))
2075 throw new ArgumentException ("Type can't be void");
2078 public static ParameterExpression Parameter (Type type, string name)
2080 if (type == null)
2081 throw new ArgumentNullException ("type");
2083 CheckNotVoid (type);
2085 return new ParameterExpression (type, name);
2088 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
2090 if (propertyAccessor == null)
2091 throw new ArgumentNullException ("propertyAccessor");
2093 CheckNonGenericMethod (propertyAccessor);
2095 if (!propertyAccessor.IsStatic) {
2096 if (expression == null)
2097 throw new ArgumentNullException ("expression");
2098 if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
2099 throw new ArgumentException ("expression");
2102 // .NET does not mandate that if the property is static, that the expression must be null
2103 // fixes a bug exposed by Orchard's ContentItemRecordAlteration.Alteration
2104 // else if (expression != null)
2105 // throw new ArgumentException ("expression");
2107 var prop = GetAssociatedProperty (propertyAccessor);
2108 if (prop == null)
2109 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
2111 return new MemberExpression (expression, prop, prop.PropertyType);
2114 static PropertyInfo GetAssociatedProperty (MethodInfo method)
2116 if (method == null)
2117 return null;
2119 foreach (var prop in method.DeclaringType.GetProperties (All)) {
2120 if (method.Equals (prop.GetGetMethod (true)))
2121 return prop;
2122 if (method.Equals (prop.GetSetMethod (true)))
2123 return prop;
2126 return null;
2129 public static MemberExpression Property (Expression expression, PropertyInfo property)
2131 if (property == null)
2132 throw new ArgumentNullException ("property");
2134 var getter = property.GetGetMethod (true);
2135 if (getter == null)
2136 throw new ArgumentException ("getter");
2138 if (!getter.IsStatic) {
2139 if (expression == null)
2140 throw new ArgumentNullException ("expression");
2141 if (!expression.Type.IsAssignableTo (property.DeclaringType))
2142 throw new ArgumentException ("expression");
2143 } else if (expression != null)
2144 throw new ArgumentException ("expression");
2146 return new MemberExpression (expression, property, property.PropertyType);
2149 public static MemberExpression Property (Expression expression, string propertyName)
2151 if (expression == null)
2152 throw new ArgumentNullException ("expression");
2154 var prop = expression.Type.GetProperty (propertyName, AllInstance);
2155 if (prop == null)
2156 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
2158 return new MemberExpression (expression, prop, prop.PropertyType);
2161 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
2163 if (expression == null)
2164 throw new ArgumentNullException ("expression");
2165 if (propertyOrFieldName == null)
2166 throw new ArgumentNullException ("propertyOrFieldName");
2168 var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
2169 if (prop != null)
2170 return new MemberExpression (expression, prop, prop.PropertyType);
2172 var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
2173 if (field != null)
2174 return new MemberExpression (expression, field, field.FieldType);
2176 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
2179 public static UnaryExpression Quote (Expression expression)
2181 if (expression == null)
2182 throw new ArgumentNullException ("expression");
2184 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
2187 public static UnaryExpression TypeAs (Expression expression, Type type)
2189 if (expression == null)
2190 throw new ArgumentNullException ("expression");
2191 if (type == null)
2192 throw new ArgumentNullException ("type");
2193 if (type.IsValueType && !type.IsNullable ())
2194 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
2196 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
2199 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
2201 if (expression == null)
2202 throw new ArgumentNullException ("expression");
2203 if (type == null)
2204 throw new ArgumentNullException ("type");
2206 CheckNotVoid (type);
2208 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
2211 public static UnaryExpression UnaryPlus (Expression expression)
2213 return UnaryPlus (expression, null);
2216 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
2218 method = UnaryCoreCheck ("op_UnaryPlus", expression, method, type => IsNumber (type));
2220 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
2223 static bool IsInt (Type t)
2225 return t == typeof (byte) || t == typeof (sbyte) ||
2226 t == typeof (short) || t == typeof (ushort) ||
2227 t == typeof (int) || t == typeof (uint) ||
2228 t == typeof (long) || t == typeof (ulong);
2231 static bool IsIntOrBool (Type t)
2233 return IsInt (t) || t == typeof (bool);
2236 static bool IsNumber (Type t)
2238 if (IsInt (t))
2239 return true;
2241 return t == typeof (float) || t == typeof (double);
2244 static bool IsSignedNumber (Type t)
2246 return IsNumber (t) && !IsUnsigned (t);
2249 internal static bool IsUnsigned (Type t)
2251 #if !TARGET_JVM
2252 if (t.IsPointer)
2253 return IsUnsigned (t.GetElementType ());
2255 #endif
2256 return t == typeof (ushort) ||
2257 t == typeof (uint) ||
2258 t == typeof (ulong) ||
2259 t == typeof (byte);
2263 // This method must be overwritten by derived classes to
2264 // compile the expression
2266 internal virtual void Emit (EmitContext ec)
2268 throw new NotImplementedException (String.Format ("Emit method is not implemented in expression type {0}", GetType ()));