5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
8 // (C) 2008 Novell, Inc. (http://www.novell.com)
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.
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.ObjectModel;
35 using System.Reflection;
36 using System.Reflection.Emit;
38 namespace System.Linq.Expressions {
40 public abstract class Expression {
42 ExpressionType node_type;
45 const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
46 const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
47 const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
48 const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
49 const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
51 public ExpressionType NodeType {
52 get { return node_type; }
59 protected Expression (ExpressionType node_type, Type type)
61 this.node_type = node_type;
65 public override string ToString ()
67 return ExpressionPrinter.ToString (this);
70 #region Binary Expressions
72 static MethodInfo GetUnaryOperator (string oper_name, Type on_type, Type type)
74 var methods = on_type.GetMethods (PublicStatic);
76 foreach (var method in methods) {
77 if (method.Name != oper_name)
80 var parameters = method.GetParameters ();
81 if (parameters.Length != 1)
84 if (!IsAssignableToParameterType (type, parameters [0]))
93 static bool IsAssignableToParameterType (Type type, ParameterInfo param)
95 return GetNotNullableOf (type).IsAssignableTo (param.ParameterType);
98 static void CheckUnaryMethod (MethodInfo method, Type param)
100 if (method.ReturnType == typeof (void))
101 throw new ArgumentException ("Specified method must return a value", "method");
103 if (!method.IsStatic)
104 throw new ArgumentException ("Method must be static", "method");
106 var parameters = method.GetParameters ();
108 if (parameters.Length != 1)
109 throw new ArgumentException ("Must have only one parameters", "method");
111 if (!IsAssignableToParameterType (param, parameters [0]))
112 throw new InvalidOperationException ("left-side argument type does not match left expression type");
116 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method, Func<Type, bool> validator)
118 if (expression == null)
119 throw new ArgumentNullException ("expression");
121 if (method != null) {
122 CheckUnaryMethod (method, expression.Type);
126 var type = GetNotNullableOf (expression.Type);
128 if (validator (type))
131 if (oper_name != null) {
132 method = GetUnaryOperator (oper_name, type, expression.Type);
137 throw new InvalidOperationException (
138 String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
142 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
144 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
146 foreach (var method in methods) {
147 if (method.Name != oper_name)
150 var parameters = method.GetParameters ();
151 if (parameters.Length != 2)
154 if (!IsAssignableToParameterType (left.Type, parameters [0]))
157 if (!IsAssignableToParameterType (right.Type, parameters [1]))
160 // Method has papers in order.
168 // Performs basic checks on the incoming expressions for binary expressions
169 // and any provided MethodInfo.
171 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
174 throw new ArgumentNullException ("left");
176 throw new ArgumentNullException ("right");
179 if (method.ReturnType == typeof (void))
180 throw new ArgumentException ("Specified method must return a value", "method");
182 if (!method.IsStatic)
183 throw new ArgumentException ("Method must be static", "method");
185 var parameters = method.GetParameters ();
187 if (parameters.Length != 2)
188 throw new ArgumentException ("Must have only two parameters", "method");
190 if (!IsAssignableToParameterType (left.Type, parameters [0]))
191 throw new InvalidOperationException ("left-side argument type does not match left expression type");
193 if (!IsAssignableToParameterType (right.Type, parameters [1]))
194 throw new InvalidOperationException ("right-side argument type does not match right expression type");
198 Type ltype = left.Type;
199 Type rtype = right.Type;
200 Type ultype = GetNotNullableOf (ltype);
201 Type urtype = GetNotNullableOf (rtype);
203 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
204 if (ultype == typeof (bool)) {
205 if (ultype == urtype && ltype == rtype)
210 // Use IsNumber to avoid expensive reflection.
211 if (IsNumber (ultype)){
212 if (ultype == urtype && ltype == rtype)
215 if (oper_name != null){
216 method = GetBinaryOperator (oper_name, urtype, left, right);
222 if (oper_name != null){
223 method = GetBinaryOperator (oper_name, ultype, left, right);
229 // == and != allow reference types without operators defined.
231 if (!ltype.IsValueType && !rtype.IsValueType &&
232 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
235 throw new InvalidOperationException (
236 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
241 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
242 // only ints and bools are allowed
244 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
247 throw new ArgumentNullException ("left");
249 throw new ArgumentNullException ("right");
251 if (method == null) {
252 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
253 if (left.Type == right.Type && IsIntOrBool (left.Type))
257 method = BinaryCoreCheck (oper_name, left, right, method);
258 if (method == null) {
259 // The check in BinaryCoreCheck allows a bit more than we do
260 // (floats and doubles). Catch this here
261 if (left.Type == typeof (double) || left.Type == typeof (float))
262 throw new InvalidOperationException ("Types not supported");
268 static Type GetResultType (Expression expression, MethodInfo method)
270 return method == null ? expression.Type : method.ReturnType;
273 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
277 if (method == null) {
278 if (IsNullable (left.Type)) {
279 if (!IsNullable (right.Type))
280 throw new InvalidOperationException ("Assertion, internal error: left is nullable, requires right to be as well");
292 return new BinaryExpression (et, GetResultType (left, method), left, right, is_lifted, is_lifted, method, null);
295 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
299 if (method == null) {
300 is_lifted = IsNullable (expression.Type);
306 return new UnaryExpression (et, expression, GetResultType (expression, method), method, is_lifted);
309 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
312 Type ltype = left.Type;
313 Type rtype = right.Type;
314 bool lnullable = IsNullable (ltype);
315 bool rnullable = IsNullable (rtype);
318 // Implement the rules as described in "Expression.Equal" method.
319 if (method == null) {
320 if (!lnullable && !rnullable) {
323 result = typeof (bool);
324 } else if (lnullable && rnullable) {
326 result = liftToNull ? typeof(bool?) : typeof (bool);
328 throw new InvalidOperationException ("Internal error: this should have been caught in BinaryCoreCheck");
330 ParameterInfo [] pi = method.GetParameters ();
331 Type mltype = pi [0].ParameterType;
332 Type mrtype = pi [1].ParameterType;
334 if (ltype == mltype && rtype == mrtype) {
337 result = method.ReturnType;
338 } else if (ltype.IsValueType && rtype.IsValueType &&
339 ((lnullable && GetNullableOf (ltype) == mltype) ||
340 (rnullable && GetNullableOf (rtype) == mrtype))){
342 if (method.ReturnType == typeof(bool)){
343 result = liftToNull ? typeof(bool?) : typeof(bool);
346 // This behavior is not documented: what
347 // happens if the result is not typeof(bool), but
348 // the parameters are nullable: the result
349 // becomes nullable<returntype>
352 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
353 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
358 result = method.ReturnType;
362 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
368 public static BinaryExpression Add (Expression left, Expression right)
370 return Add (left, right, null);
373 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
375 method = BinaryCoreCheck ("op_Addition", left, right, method);
377 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
380 public static BinaryExpression AddChecked (Expression left, Expression right)
382 return AddChecked (left, right, null);
385 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
387 method = BinaryCoreCheck ("op_Addition", left, right, method);
389 // The check in BinaryCoreCheck allows a bit more than we do
390 // (byte, sbyte). Catch that here
391 if (method == null) {
392 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
393 throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
396 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
399 public static BinaryExpression Subtract (Expression left, Expression right)
401 return Subtract (left, right, null);
404 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
406 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
408 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
411 public static BinaryExpression SubtractChecked (Expression left, Expression right)
413 return SubtractChecked (left, right, null);
416 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
418 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
420 // The check in BinaryCoreCheck allows a bit more than we do
421 // (byte, sbyte). Catch that here
422 if (method == null) {
423 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
424 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
427 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
430 public static BinaryExpression Modulo (Expression left, Expression right)
432 return Modulo (left, right, null);
435 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
437 method = BinaryCoreCheck ("op_Modulus", left, right, method);
439 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
442 public static BinaryExpression Multiply (Expression left, Expression right)
444 return Multiply (left, right, null);
447 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
449 method = BinaryCoreCheck ("op_Multiply", left, right, method);
451 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
454 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
456 return MultiplyChecked (left, right, null);
459 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
461 method = BinaryCoreCheck ("op_Multiply", left, right, method);
463 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
466 public static BinaryExpression Divide (Expression left, Expression right)
468 return Divide (left, right, null);
471 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
473 method = BinaryCoreCheck ("op_Division", left, right, method);
475 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
478 public static BinaryExpression Power (Expression left, Expression right)
480 return Power (left, right, null);
483 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
485 method = BinaryCoreCheck (null, left, right, method);
487 if (left.Type != typeof (double))
488 throw new InvalidOperationException ("Power only supports double arguments");
490 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
496 public static BinaryExpression And (Expression left, Expression right)
498 return And (left, right, null);
501 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
503 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
505 return MakeSimpleBinary (ExpressionType.And, left, right, method);
508 public static BinaryExpression Or (Expression left, Expression right)
510 return Or (left, right, null);
513 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
515 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
517 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
520 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
522 return ExclusiveOr (left, right, null);
525 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
527 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
529 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
532 public static BinaryExpression LeftShift (Expression left, Expression right)
534 return LeftShift (left, right, null);
537 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
539 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
541 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
544 public static BinaryExpression RightShift (Expression left, Expression right)
546 return RightShift (left, right, null);
549 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
551 method = BinaryCoreCheck ("op_RightShift", left, right, method);
553 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
559 public static BinaryExpression AndAlso (Expression left, Expression right)
561 return AndAlso (left, right, null);
564 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
566 method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
568 return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
571 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
573 method = BinaryCoreCheck (oper, left, right, method);
575 if (method == null) {
576 if (GetNotNullableOf (left.Type) != typeof (bool))
577 throw new InvalidOperationException ("Only booleans are allowed");
579 // The method should have identical parameter and return types.
580 if (left.Type != right.Type || method.ReturnType != left.Type)
581 throw new ArgumentException ("left, right and return type must match");
587 public static BinaryExpression OrElse (Expression left, Expression right)
589 return OrElse (left, right, null);
592 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
594 method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
596 return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
602 public static BinaryExpression Equal (Expression left, Expression right)
604 return Equal (left, right, false, null);
607 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
609 method = BinaryCoreCheck ("op_Equality", left, right, method);
611 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
614 public static BinaryExpression NotEqual (Expression left, Expression right)
616 return NotEqual (left, right, false, null);
620 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
622 method = BinaryCoreCheck ("op_Inequality", left, right, method);
624 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
627 public static BinaryExpression GreaterThan (Expression left, Expression right)
629 return GreaterThan (left, right, false, null);
632 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
634 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
636 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
639 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
641 return GreaterThanOrEqual (left, right, false, null);
645 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
647 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
649 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
652 public static BinaryExpression LessThan (Expression left, Expression right)
654 return LessThan (left, right, false, null);
657 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
659 method = BinaryCoreCheck ("op_LessThan", left, right, method);
661 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
664 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
666 return LessThanOrEqual (left, right, false, null);
669 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
671 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
673 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
680 static void CheckArray (Expression array)
683 throw new ArgumentNullException ("array");
684 if (!array.Type.IsArray)
685 throw new ArgumentException ("The array argument must be of type array");
688 public static BinaryExpression ArrayIndex (Expression array, Expression index)
693 throw new ArgumentNullException ("index");
694 if (array.Type.GetArrayRank () != 1)
695 throw new ArgumentException ("The array argument must be a single dimensional array");
696 if (index.Type != typeof (int))
697 throw new ArgumentException ("The index must be of type int");
699 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
702 public static BinaryExpression Coalesce (Expression left, Expression right)
704 return Coalesce (left, right, null);
707 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
710 throw new ArgumentNullException ("left");
712 throw new ArgumentNullException ("right");
715 // First arg must ne nullable (either Nullable<T> or a reference type
717 if (left.Type.IsValueType && !IsNullable (left.Type))
718 throw new InvalidOperationException ("Left expression can never be null");
722 if (IsNullable (left.Type)) {
723 Type lbase = GetNullableOf (left.Type);
725 if (!IsNullable (right.Type) && right.Type.IsAssignableTo (lbase))
729 if (result == null && right.Type.IsAssignableTo (left.Type))
732 if (result == null) {
733 if (IsNullable (left.Type) && GetNullableOf (left.Type).IsAssignableTo (right.Type))
738 throw new ArgumentException ("Incompatible argument types");
741 // FIXME: What do we do with "conversion"?
743 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
747 // MakeBinary constructors
749 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
751 return MakeBinary (binaryType, left, right, false, null);
754 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
756 return MakeBinary (binaryType, left, right, liftToNull, method, null);
759 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
761 switch (binaryType) {
762 case ExpressionType.Add:
763 return Add (left, right, method);
764 case ExpressionType.AddChecked:
765 return AddChecked (left, right, method);
766 case ExpressionType.AndAlso:
767 return AndAlso (left, right);
768 case ExpressionType.Coalesce:
769 return Coalesce (left, right, conversion);
770 case ExpressionType.Divide:
771 return Divide (left, right, method);
772 case ExpressionType.Equal:
773 return Equal (left, right, liftToNull, method);
774 case ExpressionType.ExclusiveOr:
775 return ExclusiveOr (left, right, method);
776 case ExpressionType.GreaterThan:
777 return GreaterThan (left, right, liftToNull, method);
778 case ExpressionType.GreaterThanOrEqual:
779 return GreaterThanOrEqual (left, right, liftToNull, method);
780 case ExpressionType.LeftShift:
781 return LeftShift (left, right, method);
782 case ExpressionType.LessThan:
783 return LessThan (left, right, liftToNull, method);
784 case ExpressionType.LessThanOrEqual:
785 return LessThanOrEqual (left, right, liftToNull, method);
786 case ExpressionType.Modulo:
787 return Modulo (left, right, method);
788 case ExpressionType.Multiply:
789 return Multiply (left, right, method);
790 case ExpressionType.MultiplyChecked:
791 return MultiplyChecked (left, right, method);
792 case ExpressionType.NotEqual:
793 return NotEqual (left, right, liftToNull, method);
794 case ExpressionType.OrElse:
795 return OrElse (left, right);
796 case ExpressionType.Power:
797 return Power (left, right, method);
798 case ExpressionType.RightShift:
799 return RightShift (left, right, method);
800 case ExpressionType.Subtract:
801 return Subtract (left, right, method);
802 case ExpressionType.SubtractChecked:
803 return SubtractChecked (left, right, method);
804 case ExpressionType.And:
805 return And (left, right, method);
806 case ExpressionType.Or:
807 return Or (left, right, method);
810 throw new ArgumentException ("MakeBinary expect a binary node type");
815 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
817 return ArrayIndex (array, indexes as IEnumerable<Expression>);
820 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
825 throw new ArgumentNullException ("indexes");
827 var args = indexes.ToReadOnlyCollection ();
828 if (array.Type.GetArrayRank () != args.Count)
829 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
831 foreach (var arg in args)
832 if (arg.Type != typeof (int))
833 throw new ArgumentException ("The index must be of type int");
835 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
838 public static UnaryExpression ArrayLength (Expression array)
841 throw new ArgumentNullException ("array");
842 if (!array.Type.IsArray)
843 throw new ArgumentException ("The type of the expression must me Array");
844 if (array.Type.GetArrayRank () != 1)
845 throw new ArgumentException ("The array must be a single dimensional array");
847 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
850 public static MemberAssignment Bind (MemberInfo member, Expression expression)
853 throw new ArgumentNullException ("member");
854 if (expression == null)
855 throw new ArgumentNullException ("expression");
859 var prop = member as PropertyInfo;
860 if (prop != null && prop.GetSetMethod (true) != null)
861 type = prop.PropertyType;
863 var field = member as FieldInfo;
865 type = field.FieldType;
868 throw new ArgumentException ("member");
870 if (!expression.Type.IsAssignableTo (type))
871 throw new ArgumentException ("member");
873 return new MemberAssignment (member, expression);
876 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
878 if (propertyAccessor == null)
879 throw new ArgumentNullException ("propertyAccessor");
880 if (expression == null)
881 throw new ArgumentNullException ("expression");
883 var prop = GetAssociatedProperty (propertyAccessor);
885 throw new ArgumentException ("propertyAccessor");
887 var setter = prop.GetSetMethod (true);
889 throw new ArgumentException ("setter");
891 if (!expression.Type.IsAssignableTo (prop.PropertyType))
892 throw new ArgumentException ("member");
894 return new MemberAssignment (prop, expression);
897 public static MethodCallExpression Call (Expression instance, MethodInfo method)
899 return Call (instance, method, null as IEnumerable<Expression>);
902 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
904 return Call (null, method, arguments as IEnumerable<Expression>);
907 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
909 return Call (instance, method, arguments as IEnumerable<Expression>);
912 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
915 throw new ArgumentNullException ("method");
916 if (instance == null && !method.IsStatic)
917 throw new ArgumentNullException ("instance");
918 if (!method.IsStatic && !instance.Type.IsAssignableTo (method.DeclaringType))
919 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
921 var args = arguments.ToReadOnlyCollection ();
923 CheckMethodArguments (method, args);
925 return new MethodCallExpression (instance, method, args);
928 static Type [] CollectTypes (IEnumerable<Expression> expressions)
930 return (from arg in expressions select arg.Type).ToArray ();
933 static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
938 if (!method.IsGenericMethod && args == null)
941 if (args.Length == method.GetGenericArguments ().Length)
942 return method.MakeGenericMethod (args);
947 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
949 if (instance == null)
950 throw new ArgumentNullException ("instance");
951 if (methodName == null)
952 throw new ArgumentNullException ("methodName");
954 var method = GetGenericMethod (instance.Type, methodName, AllInstance,
955 CollectTypes (arguments), typeArguments);
957 var args = arguments.ToReadOnlyCollection ();
958 CheckMethodArguments (method, args);
960 return new MethodCallExpression (instance, method, args);
963 static MethodInfo GetGenericMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
965 var method = type.GetMethod (methodName, flags, null, parameterTypes, null);
966 method = TryMakeGeneric (method, argumentTypes);
970 throw new InvalidOperationException ("No such method");
973 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
976 throw new ArgumentNullException ("type");
977 if (methodName == null)
978 throw new ArgumentNullException ("methodName");
980 var method = GetGenericMethod (type, methodName, AllStatic,
981 CollectTypes (arguments), typeArguments);
983 var args = arguments.ToReadOnlyCollection ();
984 CheckMethodArguments (method, args);
986 return new MethodCallExpression (method, args);
989 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
992 throw new ArgumentNullException ("test");
994 throw new ArgumentNullException ("ifTrue");
996 throw new ArgumentNullException ("ifFalse");
997 if (test.Type != typeof (bool))
998 throw new ArgumentException ("Test expression should be of type bool");
999 if (ifTrue.Type != ifFalse.Type)
1000 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1002 return new ConditionalExpression (test, ifTrue, ifFalse);
1005 public static ConstantExpression Constant (object value)
1008 return new ConstantExpression (null, typeof (object));
1010 return Constant (value, value.GetType ());
1013 public static ConstantExpression Constant (object value, Type type)
1016 throw new ArgumentNullException ("type");
1019 // value must be compatible with type, no conversions
1023 if (type.IsValueType && !IsNullable (type))
1024 throw new ArgumentException ();
1026 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
1027 throw new ArgumentException ();
1031 return new ConstantExpression (value, type);
1034 static bool IsConvertiblePrimitive (Type type)
1036 var t = GetNotNullableOf (type);
1038 if (t == typeof (bool))
1044 return t.IsPrimitive;
1047 static bool CheckPrimitiveConversion (Type type, Type target)
1052 if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
1058 static bool CheckReferenceConversion (Type type, Type target)
1063 if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
1066 if (type == typeof (object) || target == typeof (object))
1069 if (type.IsInterface || target.IsInterface)
1075 public static UnaryExpression Convert (Expression expression, Type type)
1077 return Convert (expression, type, null);
1080 static MethodInfo CheckUserConversion (Type type)
1082 var method = GetUnaryOperator ("op_Explicit", type, type);
1084 method = GetUnaryOperator ("op_Implicit", type, type);
1086 throw new InvalidOperationException ();
1091 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1093 if (expression == null)
1094 throw new ArgumentNullException ("expression");
1096 throw new ArgumentNullException ("type");
1098 var et = expression.Type;
1101 CheckUnaryMethod (method, et);
1102 else if (!CheckPrimitiveConversion (et, type) && !CheckReferenceConversion (et, type))
1103 method = CheckUserConversion (et);
1105 return new UnaryExpression (ExpressionType.Convert,
1106 expression, type, method,
1107 IsConvertNodeLifted (method, expression, type));
1110 static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
1113 return IsNullable (operand.Type) || IsNullable (target);
1115 if (IsNullable (operand.Type) && !ParameterMatch (method, operand.Type))
1118 if (IsNullable (target) && !ReturnTypeMatch (method, target))
1124 static bool ParameterMatch (MethodInfo method, Type type)
1126 return method.GetParameters () [0].ParameterType == type;
1129 static bool ReturnTypeMatch (MethodInfo method, Type type)
1131 return method.ReturnType == type;
1134 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1136 return ConvertChecked (expression, type, null);
1139 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1141 if (expression == null)
1142 throw new ArgumentNullException ("expression");
1144 throw new ArgumentNullException ("type");
1146 var et = expression.Type;
1149 CheckUnaryMethod (method, et);
1150 else if (CheckReferenceConversion (et, type))
1151 return Convert (expression, type, method);
1152 else if (!CheckPrimitiveConversion (et, type))
1153 method = CheckUserConversion (et);
1155 return new UnaryExpression (ExpressionType.ConvertChecked,
1156 expression, type, method,
1157 IsConvertNodeLifted (method, expression, type));
1160 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1162 return ElementInit (addMethod, arguments as IEnumerable<Expression>);
1165 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1167 if (addMethod == null)
1168 throw new ArgumentNullException ("addMethod");
1169 if (arguments == null)
1170 throw new ArgumentNullException ("arguments");
1171 if (addMethod.Name.ToLowerInvariant () != "add")
1172 throw new ArgumentException ("addMethod");
1173 if (addMethod.IsStatic)
1174 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1176 var args = arguments.ToReadOnlyCollection ();
1178 CheckMethodArguments (addMethod, args);
1180 return new ElementInit (addMethod, args);
1183 public static MemberExpression Field (Expression expression, FieldInfo field)
1186 throw new ArgumentNullException ("field");
1187 if (!field.IsStatic) {
1188 if (expression == null)
1189 throw new ArgumentNullException ("expression");
1190 if (!expression.Type.IsAssignableTo (field.DeclaringType))
1191 throw new ArgumentException ("field");
1194 return new MemberExpression (expression, field, field.FieldType);
1197 public static MemberExpression Field (Expression expression, string fieldName)
1199 if (expression == null)
1200 throw new ArgumentNullException ("expression");
1202 var field = expression.Type.GetField (fieldName, AllInstance);
1204 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1206 return new MemberExpression (expression, field, field.FieldType);
1209 public static Type GetActionType (params Type [] typeArgs)
1211 if (typeArgs == null)
1212 throw new ArgumentNullException ("typeArgs");
1214 if (typeArgs.Length > 4)
1215 throw new ArgumentException ("No Action type of this arity");
1217 if (typeArgs.Length == 0)
1218 return typeof (Action);
1221 switch (typeArgs.Length) {
1223 action = typeof (Action<>);
1226 action = typeof (Action<,>);
1229 action = typeof (Action<,,>);
1232 action = typeof (Action<,,,>);
1236 return action.MakeGenericType (typeArgs);
1239 public static Type GetFuncType (params Type [] typeArgs)
1241 if (typeArgs == null)
1242 throw new ArgumentNullException ("typeArgs");
1244 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1245 throw new ArgumentException ("No Func type of this arity");
1248 switch (typeArgs.Length) {
1250 func = typeof (Func<>);
1253 func = typeof (Func<,>);
1256 func = typeof (Func<,,>);
1259 func = typeof (Func<,,,>);
1262 func = typeof (Func<,,,,>);
1266 return func.MakeGenericType (typeArgs);
1269 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1271 return Invoke (expression, arguments as IEnumerable<Expression>);
1274 static Type GetInvokableType (Type t)
1276 if (t.IsAssignableTo (typeof (Delegate)))
1279 return GetGenericType (t, typeof (Expression<>));
1282 static Type GetGenericType (Type t, Type def)
1287 if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
1290 return GetGenericType (t.BaseType, def);
1293 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1295 if (expression == null)
1296 throw new ArgumentNullException ("expression");
1298 var type = GetInvokableType (expression.Type);
1300 throw new ArgumentException ("The type of the expression is not invokable");
1302 var args = arguments.ToReadOnlyCollection ();
1303 CheckForNull (args, "arguments");
1305 var invoke = type.GetMethod ("Invoke");
1307 throw new ArgumentException ("expression");
1309 if (invoke.GetParameters ().Length != args.Count)
1310 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1312 CheckMethodArguments (invoke, args);
1314 return new InvocationExpression (expression, invoke.ReturnType, args);
1317 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1319 return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1322 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1325 throw new ArgumentNullException ("body");
1327 return new Expression<TDelegate> (body, parameters.ToReadOnlyCollection ());
1330 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1333 throw new ArgumentNullException ("body");
1334 if (parameters.Length > 4)
1335 throw new ArgumentException ("Too many parameters");
1337 return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1340 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1342 if (parameters == null)
1343 parameters = new ParameterExpression [0];
1345 if (return_type == typeof (void))
1346 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1348 var types = new Type [parameters.Length + 1];
1349 for (int i = 0; i < types.Length - 1; i++)
1350 types [i] = parameters [i].Type;
1352 types [types.Length - 1] = return_type;
1353 return GetFuncType (types);
1356 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1358 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1361 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1363 if (delegateType == null)
1364 throw new ArgumentNullException ("delegateType");
1366 throw new ArgumentNullException ("body");
1368 return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1371 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1373 return ListBind (member, initializers as IEnumerable<ElementInit>);
1376 static void CheckIsAssignableToIEnumerable (Type t)
1378 if (!t.IsAssignableTo (typeof (IEnumerable)))
1379 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
1382 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1385 throw new ArgumentNullException ("member");
1386 if (initializers == null)
1387 throw new ArgumentNullException ("initializers");
1389 var inits = initializers.ToReadOnlyCollection ();
1390 CheckForNull (inits, "initializers");
1392 member.OnFieldOrProperty (
1393 field => CheckIsAssignableToIEnumerable (field.FieldType),
1394 prop => CheckIsAssignableToIEnumerable (prop.PropertyType));
1396 return new MemberListBinding (member, inits);
1399 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1401 return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
1404 static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
1406 foreach (var t in collection)
1408 throw new ArgumentNullException (name);
1411 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1413 if (propertyAccessor == null)
1414 throw new ArgumentNullException ("propertyAccessor");
1415 if (initializers == null)
1416 throw new ArgumentNullException ("initializers");
1418 var inits = initializers.ToReadOnlyCollection ();
1419 CheckForNull (inits, "initializers");
1421 var prop = GetAssociatedProperty (propertyAccessor);
1423 throw new ArgumentException ("propertyAccessor");
1425 CheckIsAssignableToIEnumerable (prop.PropertyType);
1427 return new MemberListBinding (prop, inits);
1430 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1432 return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
1435 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1437 var inits = CheckListInit (newExpression, initializers);
1439 return new ListInitExpression (newExpression, inits);
1442 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1444 return ListInit (newExpression, initializers as IEnumerable<Expression>);
1447 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1449 var inits = CheckListInit (newExpression, initializers);
1451 var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
1452 if (add_method == null)
1453 throw new InvalidOperationException ("No suitable add method found");
1455 return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
1458 static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
1460 return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
1463 static MethodInfo GetAddMethod (Type type, Type arg)
1465 return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
1468 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1470 return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
1473 static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
1475 if (newExpression == null)
1476 throw new ArgumentNullException ("newExpression");
1477 if (initializers == null)
1478 throw new ArgumentNullException ("initializers");
1479 if (!newExpression.Type.IsAssignableTo (typeof (IEnumerable)))
1480 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1482 var inits = initializers.ToReadOnlyCollection ();
1483 if (inits.Count == 0)
1484 throw new ArgumentException ("Empty initializers");
1486 CheckForNull (inits, "initializers");
1491 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1493 var inits = CheckListInit (newExpression, initializers);
1495 if (addMethod != null) {
1496 if (addMethod.Name.ToLowerInvariant () != "add")
1497 throw new ArgumentException ("addMethod");
1499 var parameters = addMethod.GetParameters ();
1500 if (parameters.Length != 1)
1501 throw new ArgumentException ("addMethod");
1503 foreach (var expression in inits)
1504 if (!IsAssignableToParameterType (expression.Type, parameters [0]))
1505 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1508 if (addMethod == null)
1509 addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
1511 if (addMethod == null)
1512 throw new InvalidOperationException ("No suitable add method found");
1514 return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
1517 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1519 if (expression == null)
1520 throw new ArgumentNullException ("expression");
1522 throw new ArgumentNullException ("member");
1524 var field = member as FieldInfo;
1526 return Field (expression, field);
1528 var property = member as PropertyInfo;
1529 if (property != null)
1530 return Property (expression, property);
1532 throw new ArgumentException ("Member should either be a field or a property");
1535 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1537 return MakeUnary (unaryType, operand, type, null);
1540 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1542 switch (unaryType) {
1543 case ExpressionType.ArrayLength:
1544 return ArrayLength (operand);
1545 case ExpressionType.Convert:
1546 return Convert (operand, type, method);
1547 case ExpressionType.ConvertChecked:
1548 return ConvertChecked (operand, type, method);
1549 case ExpressionType.Negate:
1550 return Negate (operand, method);
1551 case ExpressionType.NegateChecked:
1552 return NegateChecked (operand, method);
1553 case ExpressionType.Not:
1554 return Not (operand, method);
1555 case ExpressionType.Quote:
1556 return Quote (operand);
1557 case ExpressionType.TypeAs:
1558 return TypeAs (operand, type);
1559 case ExpressionType.UnaryPlus:
1560 return UnaryPlus (operand, method);
1563 throw new ArgumentException ("MakeUnary expect an unary operator");
1566 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
1568 return MemberBind (member, bindings as IEnumerable<MemberBinding>);
1571 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
1574 throw new ArgumentNullException ("member");
1576 var type = member.OnFieldOrProperty (
1577 field => field.FieldType,
1578 prop => prop.PropertyType);
1580 return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
1583 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
1585 return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
1588 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
1590 if (propertyAccessor == null)
1591 throw new ArgumentNullException ("propertyAccessor");
1593 var bds = bindings.ToReadOnlyCollection ();
1594 CheckForNull (bds, "bindings");
1596 var prop = GetAssociatedProperty (propertyAccessor);
1598 throw new ArgumentException ("propertyAccessor");
1600 return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
1603 static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
1605 if (bindings == null)
1606 throw new ArgumentNullException ("bindings");
1608 var bds = bindings.ToReadOnlyCollection ();
1609 CheckForNull (bds, "bindings");
1611 foreach (var binding in bds)
1612 if (!type.IsAssignableTo (binding.Member.DeclaringType))
1613 throw new ArgumentException ("Type not assignable to member type");
1618 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
1620 return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
1623 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
1625 if (newExpression == null)
1626 throw new ArgumentNullException ("newExpression");
1628 return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
1631 public static UnaryExpression Negate (Expression expression)
1633 return Negate (expression, null);
1636 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1638 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1640 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1643 public static UnaryExpression NegateChecked (Expression expression)
1645 return NegateChecked (expression, null);
1648 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1650 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1652 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1655 public static NewExpression New (ConstructorInfo constructor)
1657 if (constructor == null)
1658 throw new ArgumentNullException ("constructor");
1660 if (constructor.GetParameters ().Length > 0)
1661 throw new ArgumentException ("Constructor must be parameter less");
1663 return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
1666 public static NewExpression New (Type type)
1669 throw new ArgumentNullException ("type");
1671 var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
1673 if (type.IsValueType)
1674 return new NewExpression (type, args);
1676 var ctor = type.GetConstructor (Type.EmptyTypes);
1678 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1680 return new NewExpression (ctor, args, null);
1683 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1685 return New (constructor, arguments as IEnumerable<Expression>);
1688 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1690 if (constructor == null)
1691 throw new ArgumentNullException ("constructor");
1693 var args = arguments.ToReadOnlyCollection ();
1695 CheckMethodArguments (constructor, args);
1697 return new NewExpression (constructor, args, null);
1700 static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
1702 var parameters = method.GetParameters ();
1704 if (arguments.Count != parameters.Length)
1705 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1707 for (int i = 0; i < parameters.Length; i++) {
1708 if (arguments [i] == null)
1709 throw new ArgumentNullException ("arguments");
1711 if (!IsAssignableToParameterType (arguments [i].Type, parameters [i]))
1712 throw new ArgumentException ("arguments");
1716 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1718 return New (constructor, arguments, members as IEnumerable<MemberInfo>);
1721 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1723 if (constructor == null)
1724 throw new ArgumentNullException ("constructor");
1726 var args = arguments.ToReadOnlyCollection ();
1727 var mmbs = members.ToReadOnlyCollection ();
1729 CheckForNull (args, "arguments");
1730 CheckForNull (mmbs, "members");
1732 CheckMethodArguments (constructor, args);
1734 if (args.Count != mmbs.Count)
1735 throw new ArgumentException ("Arguments count does not match members count");
1737 for (int i = 0; i < mmbs.Count; i++) {
1738 var member = mmbs [i];
1740 switch (member.MemberType) {
1741 case MemberTypes.Field:
1742 type = (member as FieldInfo).FieldType;
1744 case MemberTypes.Method:
1745 type = (member as MethodInfo).ReturnType;
1747 case MemberTypes.Property:
1748 var prop = member as PropertyInfo;
1749 if (prop.GetGetMethod (true) == null)
1750 throw new ArgumentException ("Property must have a getter");
1752 type = (member as PropertyInfo).PropertyType;
1755 throw new ArgumentException ("Member type not allowed");
1758 if (!args [i].Type.IsAssignableTo (type))
1759 throw new ArgumentException ("Argument type not assignable to member type");
1762 return new NewExpression (constructor, args, mmbs);
1765 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1767 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1770 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1773 throw new ArgumentNullException ("type");
1775 throw new ArgumentNullException ("bounds");
1777 var array_bounds = bounds.ToReadOnlyCollection ();
1778 foreach (var expression in array_bounds)
1779 if (!IsInt (expression.Type))
1780 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1782 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1785 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1787 return NewArrayInit (type, initializers as IEnumerable<Expression>);
1790 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1793 throw new ArgumentNullException ("type");
1794 if (initializers == null)
1795 throw new ArgumentNullException ("initializers");
1797 var array_initializers = initializers.ToReadOnlyCollection ();
1799 foreach (var expression in initializers) {
1800 if (expression == null)
1801 throw new ArgumentNullException ("initializers");
1803 if (!expression.Type.IsAssignableTo (type))
1804 throw new InvalidOperationException ();
1806 // TODO: Quote elements if type == typeof (Expression)
1809 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
1812 public static UnaryExpression Not (Expression expression)
1814 return Not (expression, null);
1817 public static UnaryExpression Not (Expression expression, MethodInfo method)
1819 Func<Type, bool> validator = type => IsIntOrBool (type);
1821 method = UnaryCoreCheck ("op_LogicalNot", expression, method, validator);
1824 method = UnaryCoreCheck ("op_OnesComplement", expression, method, validator);
1826 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1829 public static ParameterExpression Parameter (Type type, string name)
1832 throw new ArgumentNullException ("type");
1834 return new ParameterExpression (type, name);
1837 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1839 if (propertyAccessor == null)
1840 throw new ArgumentNullException ("propertyAccessor");
1842 if (!propertyAccessor.IsStatic) {
1843 if (expression == null)
1844 throw new ArgumentNullException ("expression");
1845 if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
1846 throw new ArgumentException ("expression");
1849 var prop = GetAssociatedProperty (propertyAccessor);
1851 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
1853 return new MemberExpression (expression, prop, prop.PropertyType);
1856 static PropertyInfo GetAssociatedProperty (MethodInfo method)
1858 foreach (var prop in method.DeclaringType.GetProperties (All)) {
1859 if (prop.GetGetMethod (true) == method)
1861 if (prop.GetSetMethod (true) == method)
1868 public static MemberExpression Property (Expression expression, PropertyInfo property)
1870 if (property == null)
1871 throw new ArgumentNullException ("property");
1873 var getter = property.GetGetMethod (true);
1875 throw new ArgumentException ("getter");
1877 if (!getter.IsStatic) {
1878 if (expression == null)
1879 throw new ArgumentNullException ("expression");
1880 if (!expression.Type.IsAssignableTo (property.DeclaringType))
1881 throw new ArgumentException ("expression");
1884 return new MemberExpression (expression, property, property.PropertyType);
1887 public static MemberExpression Property (Expression expression, string propertyName)
1889 if (expression == null)
1890 throw new ArgumentNullException ("expression");
1892 var prop = expression.Type.GetProperty (propertyName, AllInstance);
1894 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
1896 return new MemberExpression (expression, prop, prop.PropertyType);
1899 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1901 if (expression == null)
1902 throw new ArgumentNullException ("expression");
1903 if (propertyOrFieldName == null)
1904 throw new ArgumentNullException ("propertyOrFieldName");
1906 var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
1908 return new MemberExpression (expression, prop, prop.PropertyType);
1910 var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
1912 return new MemberExpression (expression, field, field.FieldType);
1914 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
1917 public static UnaryExpression Quote (Expression expression)
1919 if (expression == null)
1920 throw new ArgumentNullException ("expression");
1922 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1925 public static UnaryExpression TypeAs (Expression expression, Type type)
1927 if (expression == null)
1928 throw new ArgumentNullException ("expression");
1930 throw new ArgumentNullException ("type");
1931 if (type.IsValueType && !IsNullable (type))
1932 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1934 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1937 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1939 if (expression == null)
1940 throw new ArgumentNullException ("expression");
1942 throw new ArgumentNullException ("type");
1944 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1947 public static UnaryExpression UnaryPlus (Expression expression)
1949 return UnaryPlus (expression, null);
1952 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1954 method = UnaryCoreCheck ("op_UnaryPlus", expression, method, type => IsNumber (type));
1956 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1959 static bool IsInt (Type t)
1961 return t == typeof (byte) || t == typeof (sbyte) ||
1962 t == typeof (short) || t == typeof (ushort) ||
1963 t == typeof (int) || t == typeof (uint) ||
1964 t == typeof (long) || t == typeof (ulong);
1967 static bool IsIntOrBool (Type t)
1969 return IsInt (t) || t == typeof (bool);
1972 static bool IsNumber (Type t)
1977 return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
1980 internal static bool IsNullable (Type type)
1982 return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1985 static bool IsSignedNumber (Type t)
1987 return IsNumber (t) && !IsUnsigned (t);
1990 internal static bool IsUnsigned (Type t)
1993 return IsUnsigned (t.GetElementType ());
1995 return t == typeof (ushort) ||
1996 t == typeof (uint) ||
1997 t == typeof (ulong) ||
2002 // returns the T in a a Nullable<T> type.
2004 internal static Type GetNullableOf (Type type)
2006 return type.GetGenericArguments () [0];
2009 internal static Type GetNotNullableOf (Type type)
2011 return IsNullable (type) ? GetNullableOf (type) : type;
2015 // This method must be overwritten by derived classes to
2016 // compile the expression
2018 internal abstract void Emit (EmitContext ec);