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 NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance;
47 const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
48 const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
49 const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
50 const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
52 public ExpressionType NodeType {
53 get { return node_type; }
60 protected Expression (ExpressionType node_type, Type type)
62 this.node_type = node_type;
66 public override string ToString ()
68 return ExpressionPrinter.ToString (this);
71 #region Binary Expressions
73 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param)
75 return GetUnaryOperator (oper_name, declaring, param, null);
78 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param, Type ret)
80 var methods = declaring.GetMethods (PublicStatic);
82 foreach (var method in methods) {
83 if (method.Name != oper_name)
86 var parameters = method.GetParameters ();
87 if (parameters.Length != 1)
90 if (!IsAssignableToParameterType (param, parameters [0]))
93 if (ret != null && method.ReturnType != GetNotNullableOf (ret))
102 static bool IsAssignableToParameterType (Type type, ParameterInfo param)
104 var ptype = param.ParameterType;
106 ptype = ptype.GetElementType ();
108 return GetNotNullableOf (type).IsAssignableTo (ptype);
111 static MethodInfo CheckUnaryMethod (MethodInfo method, Type param)
113 if (method.ReturnType == typeof (void))
114 throw new ArgumentException ("Specified method must return a value", "method");
116 if (!method.IsStatic)
117 throw new ArgumentException ("Method must be static", "method");
119 var parameters = method.GetParameters ();
121 if (parameters.Length != 1)
122 throw new ArgumentException ("Must have only one parameters", "method");
124 if (!IsAssignableToParameterType (param, parameters [0]))
125 throw new InvalidOperationException ("left-side argument type does not match expression type");
130 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method, Func<Type, bool> validator)
132 if (expression == null)
133 throw new ArgumentNullException ("expression");
136 return CheckUnaryMethod (method, expression.Type);
138 var type = GetNotNullableOf (expression.Type);
140 if (validator (type))
143 if (oper_name != null) {
144 method = GetUnaryOperator (oper_name, type, expression.Type);
149 throw new InvalidOperationException (
150 string.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
153 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
155 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
157 foreach (var method in methods) {
158 if (method.Name != oper_name)
161 var parameters = method.GetParameters ();
162 if (parameters.Length != 2)
165 if (!IsAssignableToParameterType (left.Type, parameters [0]))
168 if (!IsAssignableToParameterType (right.Type, parameters [1]))
171 // Method has papers in order.
179 // Performs basic checks on the incoming expressions for binary expressions
180 // and any provided MethodInfo.
182 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
185 throw new ArgumentNullException ("left");
187 throw new ArgumentNullException ("right");
190 if (method.ReturnType == typeof (void))
191 throw new ArgumentException ("Specified method must return a value", "method");
193 if (!method.IsStatic)
194 throw new ArgumentException ("Method must be static", "method");
196 var parameters = method.GetParameters ();
198 if (parameters.Length != 2)
199 throw new ArgumentException ("Must have only two parameters", "method");
201 if (!IsAssignableToParameterType (left.Type, parameters [0]))
202 throw new InvalidOperationException ("left-side argument type does not match left expression type");
204 if (!IsAssignableToParameterType (right.Type, parameters [1]))
205 throw new InvalidOperationException ("right-side argument type does not match right expression type");
209 Type ltype = left.Type;
210 Type rtype = right.Type;
211 Type ultype = GetNotNullableOf (ltype);
212 Type urtype = GetNotNullableOf (rtype);
214 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
215 if (ultype == typeof (bool)) {
216 if (ultype == urtype && ltype == rtype)
221 // Use IsNumber to avoid expensive reflection.
222 if (IsNumber (ultype)){
223 if (ultype == urtype && ltype == rtype)
226 if (oper_name != null){
227 method = GetBinaryOperator (oper_name, urtype, left, right);
233 if (oper_name != null){
234 method = GetBinaryOperator (oper_name, ultype, left, right);
240 // == and != allow reference types without operators defined.
242 if (!ltype.IsValueType && !rtype.IsValueType &&
243 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
246 throw new InvalidOperationException (
247 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
252 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
253 // only ints and bools are allowed
255 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
258 throw new ArgumentNullException ("left");
260 throw new ArgumentNullException ("right");
262 if (method == null) {
263 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
264 if (left.Type == right.Type && IsIntOrBool (left.Type))
268 method = BinaryCoreCheck (oper_name, left, right, method);
269 if (method == null) {
270 // The check in BinaryCoreCheck allows a bit more than we do
271 // (floats and doubles). Catch this here
272 if (left.Type == typeof (double) || left.Type == typeof (float))
273 throw new InvalidOperationException ("Types not supported");
279 static Type GetResultType (Expression expression, MethodInfo method)
281 return method == null ? expression.Type : method.ReturnType;
284 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
288 if (method == null) {
289 if (IsNullable (left.Type)) {
290 if (!IsNullable (right.Type))
291 throw new InvalidOperationException ("Assertion, internal error: left is nullable, requires right to be as well");
303 return new BinaryExpression (et, GetResultType (left, method), left, right, is_lifted, is_lifted, method, null);
306 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
310 if (method == null) {
311 is_lifted = IsNullable (expression.Type);
317 return new UnaryExpression (et, expression, GetResultType (expression, method), method, is_lifted);
320 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
323 Type ltype = left.Type;
324 Type rtype = right.Type;
325 bool lnullable = IsNullable (ltype);
326 bool rnullable = IsNullable (rtype);
329 // Implement the rules as described in "Expression.Equal" method.
330 if (method == null) {
331 if (!lnullable && !rnullable) {
334 result = typeof (bool);
335 } else if (lnullable && rnullable) {
337 result = liftToNull ? typeof(bool?) : typeof (bool);
339 throw new InvalidOperationException ("Internal error: this should have been caught in BinaryCoreCheck");
341 ParameterInfo [] pi = method.GetParameters ();
342 Type mltype = pi [0].ParameterType;
343 Type mrtype = pi [1].ParameterType;
345 if (ltype == mltype && rtype == mrtype) {
348 result = method.ReturnType;
349 } else if (ltype.IsValueType && rtype.IsValueType &&
350 ((lnullable && GetNullableOf (ltype) == mltype) ||
351 (rnullable && GetNullableOf (rtype) == mrtype))){
353 if (method.ReturnType == typeof(bool)){
354 result = liftToNull ? typeof(bool?) : typeof(bool);
357 // This behavior is not documented: what
358 // happens if the result is not typeof(bool), but
359 // the parameters are nullable: the result
360 // becomes nullable<returntype>
363 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
364 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
369 result = method.ReturnType;
373 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
379 public static BinaryExpression Add (Expression left, Expression right)
381 return Add (left, right, null);
384 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
386 method = BinaryCoreCheck ("op_Addition", left, right, method);
388 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
391 public static BinaryExpression AddChecked (Expression left, Expression right)
393 return AddChecked (left, right, null);
396 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
398 method = BinaryCoreCheck ("op_Addition", left, right, method);
400 // The check in BinaryCoreCheck allows a bit more than we do
401 // (byte, sbyte). Catch that here
402 if (method == null) {
403 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
404 throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
407 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
410 public static BinaryExpression Subtract (Expression left, Expression right)
412 return Subtract (left, right, null);
415 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
417 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
419 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
422 public static BinaryExpression SubtractChecked (Expression left, Expression right)
424 return SubtractChecked (left, right, null);
427 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
429 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
431 // The check in BinaryCoreCheck allows a bit more than we do
432 // (byte, sbyte). Catch that here
433 if (method == null) {
434 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
435 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
438 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
441 public static BinaryExpression Modulo (Expression left, Expression right)
443 return Modulo (left, right, null);
446 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
448 method = BinaryCoreCheck ("op_Modulus", left, right, method);
450 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
453 public static BinaryExpression Multiply (Expression left, Expression right)
455 return Multiply (left, right, null);
458 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
460 method = BinaryCoreCheck ("op_Multiply", left, right, method);
462 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
465 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
467 return MultiplyChecked (left, right, null);
470 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
472 method = BinaryCoreCheck ("op_Multiply", left, right, method);
474 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
477 public static BinaryExpression Divide (Expression left, Expression right)
479 return Divide (left, right, null);
482 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
484 method = BinaryCoreCheck ("op_Division", left, right, method);
486 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
489 public static BinaryExpression Power (Expression left, Expression right)
491 return Power (left, right, null);
494 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
496 method = BinaryCoreCheck (null, left, right, method);
498 if (left.Type != typeof (double))
499 throw new InvalidOperationException ("Power only supports double arguments");
501 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
507 public static BinaryExpression And (Expression left, Expression right)
509 return And (left, right, null);
512 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
514 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
516 return MakeSimpleBinary (ExpressionType.And, left, right, method);
519 public static BinaryExpression Or (Expression left, Expression right)
521 return Or (left, right, null);
524 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
526 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
528 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
531 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
533 return ExclusiveOr (left, right, null);
536 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
538 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
540 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
543 public static BinaryExpression LeftShift (Expression left, Expression right)
545 return LeftShift (left, right, null);
548 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
550 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
552 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
555 public static BinaryExpression RightShift (Expression left, Expression right)
557 return RightShift (left, right, null);
560 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
562 method = BinaryCoreCheck ("op_RightShift", left, right, method);
564 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
570 public static BinaryExpression AndAlso (Expression left, Expression right)
572 return AndAlso (left, right, null);
575 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
577 method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
579 return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
582 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
584 method = BinaryCoreCheck (oper, left, right, method);
586 if (method == null) {
587 if (GetNotNullableOf (left.Type) != typeof (bool))
588 throw new InvalidOperationException ("Only booleans are allowed");
590 // The method should have identical parameter and return types.
591 if (left.Type != right.Type || method.ReturnType != left.Type)
592 throw new ArgumentException ("left, right and return type must match");
598 public static BinaryExpression OrElse (Expression left, Expression right)
600 return OrElse (left, right, null);
603 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
605 method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
607 return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
613 public static BinaryExpression Equal (Expression left, Expression right)
615 return Equal (left, right, false, null);
618 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
620 method = BinaryCoreCheck ("op_Equality", left, right, method);
622 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
625 public static BinaryExpression NotEqual (Expression left, Expression right)
627 return NotEqual (left, right, false, null);
631 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
633 method = BinaryCoreCheck ("op_Inequality", left, right, method);
635 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
638 public static BinaryExpression GreaterThan (Expression left, Expression right)
640 return GreaterThan (left, right, false, null);
643 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
645 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
647 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
650 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
652 return GreaterThanOrEqual (left, right, false, null);
656 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
658 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
660 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
663 public static BinaryExpression LessThan (Expression left, Expression right)
665 return LessThan (left, right, false, null);
668 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
670 method = BinaryCoreCheck ("op_LessThan", left, right, method);
672 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
675 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
677 return LessThanOrEqual (left, right, false, null);
680 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
682 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
684 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
691 static void CheckArray (Expression array)
694 throw new ArgumentNullException ("array");
695 if (!array.Type.IsArray)
696 throw new ArgumentException ("The array argument must be of type array");
699 public static BinaryExpression ArrayIndex (Expression array, Expression index)
704 throw new ArgumentNullException ("index");
705 if (array.Type.GetArrayRank () != 1)
706 throw new ArgumentException ("The array argument must be a single dimensional array");
707 if (index.Type != typeof (int))
708 throw new ArgumentException ("The index must be of type int");
710 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
713 public static BinaryExpression Coalesce (Expression left, Expression right)
715 return Coalesce (left, right, null);
718 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
721 throw new ArgumentNullException ("left");
723 throw new ArgumentNullException ("right");
726 // First arg must ne nullable (either Nullable<T> or a reference type
728 if (left.Type.IsValueType && !IsNullable (left.Type))
729 throw new InvalidOperationException ("Left expression can never be null");
733 if (IsNullable (left.Type)) {
734 Type lbase = GetNullableOf (left.Type);
736 if (!IsNullable (right.Type) && right.Type.IsAssignableTo (lbase))
740 if (result == null && right.Type.IsAssignableTo (left.Type))
743 if (result == null) {
744 if (IsNullable (left.Type) && GetNullableOf (left.Type).IsAssignableTo (right.Type))
749 throw new ArgumentException ("Incompatible argument types");
752 // FIXME: What do we do with "conversion"?
754 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
758 // MakeBinary constructors
760 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
762 return MakeBinary (binaryType, left, right, false, null);
765 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
767 return MakeBinary (binaryType, left, right, liftToNull, method, null);
770 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
772 switch (binaryType) {
773 case ExpressionType.Add:
774 return Add (left, right, method);
775 case ExpressionType.AddChecked:
776 return AddChecked (left, right, method);
777 case ExpressionType.AndAlso:
778 return AndAlso (left, right);
779 case ExpressionType.Coalesce:
780 return Coalesce (left, right, conversion);
781 case ExpressionType.Divide:
782 return Divide (left, right, method);
783 case ExpressionType.Equal:
784 return Equal (left, right, liftToNull, method);
785 case ExpressionType.ExclusiveOr:
786 return ExclusiveOr (left, right, method);
787 case ExpressionType.GreaterThan:
788 return GreaterThan (left, right, liftToNull, method);
789 case ExpressionType.GreaterThanOrEqual:
790 return GreaterThanOrEqual (left, right, liftToNull, method);
791 case ExpressionType.LeftShift:
792 return LeftShift (left, right, method);
793 case ExpressionType.LessThan:
794 return LessThan (left, right, liftToNull, method);
795 case ExpressionType.LessThanOrEqual:
796 return LessThanOrEqual (left, right, liftToNull, method);
797 case ExpressionType.Modulo:
798 return Modulo (left, right, method);
799 case ExpressionType.Multiply:
800 return Multiply (left, right, method);
801 case ExpressionType.MultiplyChecked:
802 return MultiplyChecked (left, right, method);
803 case ExpressionType.NotEqual:
804 return NotEqual (left, right, liftToNull, method);
805 case ExpressionType.OrElse:
806 return OrElse (left, right);
807 case ExpressionType.Power:
808 return Power (left, right, method);
809 case ExpressionType.RightShift:
810 return RightShift (left, right, method);
811 case ExpressionType.Subtract:
812 return Subtract (left, right, method);
813 case ExpressionType.SubtractChecked:
814 return SubtractChecked (left, right, method);
815 case ExpressionType.And:
816 return And (left, right, method);
817 case ExpressionType.Or:
818 return Or (left, right, method);
821 throw new ArgumentException ("MakeBinary expect a binary node type");
826 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
828 return ArrayIndex (array, indexes as IEnumerable<Expression>);
831 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
836 throw new ArgumentNullException ("indexes");
838 var args = indexes.ToReadOnlyCollection ();
839 if (array.Type.GetArrayRank () != args.Count)
840 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
842 foreach (var arg in args)
843 if (arg.Type != typeof (int))
844 throw new ArgumentException ("The index must be of type int");
846 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
849 public static UnaryExpression ArrayLength (Expression array)
852 throw new ArgumentNullException ("array");
853 if (!array.Type.IsArray)
854 throw new ArgumentException ("The type of the expression must me Array");
855 if (array.Type.GetArrayRank () != 1)
856 throw new ArgumentException ("The array must be a single dimensional array");
858 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
861 public static MemberAssignment Bind (MemberInfo member, Expression expression)
864 throw new ArgumentNullException ("member");
865 if (expression == null)
866 throw new ArgumentNullException ("expression");
870 var prop = member as PropertyInfo;
871 if (prop != null && prop.GetSetMethod (true) != null)
872 type = prop.PropertyType;
874 var field = member as FieldInfo;
876 type = field.FieldType;
879 throw new ArgumentException ("member");
881 if (!expression.Type.IsAssignableTo (type))
882 throw new ArgumentException ("member");
884 return new MemberAssignment (member, expression);
887 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
889 if (propertyAccessor == null)
890 throw new ArgumentNullException ("propertyAccessor");
891 if (expression == null)
892 throw new ArgumentNullException ("expression");
894 var prop = GetAssociatedProperty (propertyAccessor);
896 throw new ArgumentException ("propertyAccessor");
898 var setter = prop.GetSetMethod (true);
900 throw new ArgumentException ("setter");
902 if (!expression.Type.IsAssignableTo (prop.PropertyType))
903 throw new ArgumentException ("member");
905 return new MemberAssignment (prop, expression);
908 public static MethodCallExpression Call (Expression instance, MethodInfo method)
910 return Call (instance, method, null as IEnumerable<Expression>);
913 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
915 return Call (null, method, arguments as IEnumerable<Expression>);
918 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
920 return Call (instance, method, arguments as IEnumerable<Expression>);
923 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
926 throw new ArgumentNullException ("method");
927 if (instance == null && !method.IsStatic)
928 throw new ArgumentNullException ("instance");
929 if (!method.IsStatic && !instance.Type.IsAssignableTo (method.DeclaringType))
930 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
932 var args = arguments.ToReadOnlyCollection ();
934 CheckMethodArguments (method, args);
936 return new MethodCallExpression (instance, method, args);
939 static Type [] CollectTypes (IEnumerable<Expression> expressions)
941 return (from arg in expressions select arg.Type).ToArray ();
944 static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
949 if (!method.IsGenericMethod && args == null)
952 if (args.Length == method.GetGenericArguments ().Length)
953 return method.MakeGenericMethod (args);
958 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
960 if (instance == null)
961 throw new ArgumentNullException ("instance");
962 if (methodName == null)
963 throw new ArgumentNullException ("methodName");
965 var method = TryGetMethod (instance.Type, methodName, AllInstance,
966 CollectTypes (arguments), typeArguments);
968 var args = arguments.ToReadOnlyCollection ();
970 CheckMethodArguments (method, args);
972 return new MethodCallExpression (instance, method, args);
975 static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes)
977 if (method.Name != name)
980 var parameters = method.GetParameters ();
982 if (parameters.Length != parameterTypes.Length)
985 if (method.IsGenericMethod) // if it's a generic method, when can't compare its parameters
988 for (int i = 0; i < parameters.Length; i++)
989 if (!IsAssignableToParameterType (parameterTypes [i], parameters [i]))
995 static MethodInfo TryGetMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
997 var methods = from meth in type.GetMethods (flags)
998 where MethodMatch (meth, methodName, parameterTypes)
1001 if (methods.Count () > 1)
1002 throw new InvalidOperationException ("Too much method candidates");
1004 var method = TryMakeGeneric (methods.FirstOrDefault (), argumentTypes);
1008 throw new InvalidOperationException ("No such method");
1011 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
1014 throw new ArgumentNullException ("type");
1015 if (methodName == null)
1016 throw new ArgumentNullException ("methodName");
1018 var method = TryGetMethod (type, methodName, AllStatic,
1019 CollectTypes (arguments), typeArguments);
1021 var args = arguments.ToReadOnlyCollection ();
1023 CheckMethodArguments (method, args);
1025 return new MethodCallExpression (method, args);
1028 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
1031 throw new ArgumentNullException ("test");
1033 throw new ArgumentNullException ("ifTrue");
1034 if (ifFalse == null)
1035 throw new ArgumentNullException ("ifFalse");
1036 if (test.Type != typeof (bool))
1037 throw new ArgumentException ("Test expression should be of type bool");
1038 if (ifTrue.Type != ifFalse.Type)
1039 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1041 return new ConditionalExpression (test, ifTrue, ifFalse);
1044 public static ConstantExpression Constant (object value)
1047 return new ConstantExpression (null, typeof (object));
1049 return Constant (value, value.GetType ());
1052 public static ConstantExpression Constant (object value, Type type)
1055 throw new ArgumentNullException ("type");
1058 // value must be compatible with type, no conversions
1062 if (type.IsValueType && !IsNullable (type))
1063 throw new ArgumentException ();
1065 if (!(type.IsValueType && IsNullable (type)) && !value.GetType ().IsAssignableTo (type))
1066 throw new ArgumentException ();
1070 return new ConstantExpression (value, type);
1073 static bool IsConvertiblePrimitive (Type type)
1075 var t = GetNotNullableOf (type);
1077 if (t == typeof (bool))
1083 return t.IsPrimitive;
1086 internal static bool IsPrimitiveConversion (Type type, Type target)
1091 if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
1097 internal static bool IsReferenceConversion (Type type, Type target)
1102 if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
1105 if (type == typeof (object) || target == typeof (object))
1108 if (type.IsInterface || target.IsInterface)
1114 public static UnaryExpression Convert (Expression expression, Type type)
1116 return Convert (expression, type, null);
1119 static MethodInfo GetUserConversionMethod (Type type, Type target)
1121 var method = GetUnaryOperator ("op_Explicit", type, type, target);
1123 method = GetUnaryOperator ("op_Implicit", type, type, target);
1125 throw new InvalidOperationException ();
1130 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1132 if (expression == null)
1133 throw new ArgumentNullException ("expression");
1135 throw new ArgumentNullException ("type");
1137 var et = expression.Type;
1140 CheckUnaryMethod (method, et);
1141 else if (!IsPrimitiveConversion (et, type) && !IsReferenceConversion (et, type))
1142 method = GetUserConversionMethod (et, type);
1144 return new UnaryExpression (ExpressionType.Convert,
1145 expression, type, method,
1146 IsConvertNodeLifted (method, expression, type));
1149 static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
1152 return IsNullable (operand.Type) || IsNullable (target);
1154 if (IsNullable (operand.Type) && !ParameterMatch (method, operand.Type))
1157 if (IsNullable (target) && !ReturnTypeMatch (method, target))
1163 static bool ParameterMatch (MethodInfo method, Type type)
1165 return method.GetParameters () [0].ParameterType == type;
1168 static bool ReturnTypeMatch (MethodInfo method, Type type)
1170 return method.ReturnType == type;
1173 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1175 return ConvertChecked (expression, type, null);
1178 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1180 if (expression == null)
1181 throw new ArgumentNullException ("expression");
1183 throw new ArgumentNullException ("type");
1185 var et = expression.Type;
1188 CheckUnaryMethod (method, et);
1189 else if (IsReferenceConversion (et, type))
1190 return Convert (expression, type, method);
1191 else if (!IsPrimitiveConversion (et, type))
1192 method = GetUserConversionMethod (et, type);
1194 return new UnaryExpression (ExpressionType.ConvertChecked,
1195 expression, type, method,
1196 IsConvertNodeLifted (method, expression, type));
1199 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1201 return ElementInit (addMethod, arguments as IEnumerable<Expression>);
1204 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1206 if (addMethod == null)
1207 throw new ArgumentNullException ("addMethod");
1208 if (arguments == null)
1209 throw new ArgumentNullException ("arguments");
1210 if (addMethod.Name.ToLowerInvariant () != "add")
1211 throw new ArgumentException ("addMethod");
1212 if (addMethod.IsStatic)
1213 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1215 var args = arguments.ToReadOnlyCollection ();
1217 CheckMethodArguments (addMethod, args);
1219 return new ElementInit (addMethod, args);
1222 public static MemberExpression Field (Expression expression, FieldInfo field)
1225 throw new ArgumentNullException ("field");
1226 if (!field.IsStatic) {
1227 if (expression == null)
1228 throw new ArgumentNullException ("expression");
1229 if (!expression.Type.IsAssignableTo (field.DeclaringType))
1230 throw new ArgumentException ("field");
1233 return new MemberExpression (expression, field, field.FieldType);
1236 public static MemberExpression Field (Expression expression, string fieldName)
1238 if (expression == null)
1239 throw new ArgumentNullException ("expression");
1241 var field = expression.Type.GetField (fieldName, AllInstance);
1243 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1245 return new MemberExpression (expression, field, field.FieldType);
1248 public static Type GetActionType (params Type [] typeArgs)
1250 if (typeArgs == null)
1251 throw new ArgumentNullException ("typeArgs");
1253 if (typeArgs.Length > 4)
1254 throw new ArgumentException ("No Action type of this arity");
1256 if (typeArgs.Length == 0)
1257 return typeof (Action);
1260 switch (typeArgs.Length) {
1262 action = typeof (Action<>);
1265 action = typeof (Action<,>);
1268 action = typeof (Action<,,>);
1271 action = typeof (Action<,,,>);
1275 return action.MakeGenericType (typeArgs);
1278 public static Type GetFuncType (params Type [] typeArgs)
1280 if (typeArgs == null)
1281 throw new ArgumentNullException ("typeArgs");
1283 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1284 throw new ArgumentException ("No Func type of this arity");
1287 switch (typeArgs.Length) {
1289 func = typeof (Func<>);
1292 func = typeof (Func<,>);
1295 func = typeof (Func<,,>);
1298 func = typeof (Func<,,,>);
1301 func = typeof (Func<,,,,>);
1305 return func.MakeGenericType (typeArgs);
1308 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1310 return Invoke (expression, arguments as IEnumerable<Expression>);
1313 static Type GetInvokableType (Type t)
1315 if (t.IsAssignableTo (typeof (Delegate)))
1318 return GetGenericType (t, typeof (Expression<>));
1321 static Type GetGenericType (Type t, Type def)
1326 if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
1329 return GetGenericType (t.BaseType, def);
1332 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1334 if (expression == null)
1335 throw new ArgumentNullException ("expression");
1337 var type = GetInvokableType (expression.Type);
1339 throw new ArgumentException ("The type of the expression is not invokable");
1341 var args = arguments.ToReadOnlyCollection ();
1342 CheckForNull (args, "arguments");
1344 var invoke = type.GetMethod ("Invoke");
1346 throw new ArgumentException ("expression");
1348 if (invoke.GetParameters ().Length != args.Count)
1349 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1351 CheckMethodArguments (invoke, args);
1353 return new InvocationExpression (expression, invoke.ReturnType, args);
1356 static bool CanAssign (Type target, Type source)
1358 // This catches object and value type mixage, type compatibility is handled later
1359 if (target.IsValueType ^ source.IsValueType)
1362 return source.IsAssignableTo (target);
1365 static void CheckLambda (Type delegateType, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1367 if (!delegateType.IsSubclassOf (typeof (System.Delegate)))
1368 throw new ArgumentException ("delegateType");
1370 var invoke = delegateType.GetMethod ("Invoke", BindingFlags.Instance | BindingFlags.Public);
1372 throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
1374 var invoke_parameters = invoke.GetParameters ();
1375 if (invoke_parameters.Length != parameters.Count)
1376 throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType), "delegateType");
1378 for (int i = 0; i < invoke_parameters.Length; i++) {
1379 if (!CanAssign (parameters [i].Type, invoke_parameters [i].ParameterType))
1380 throw new ArgumentException (String.Format ("Can not assign a {0} to a {1}", invoke_parameters [i].ParameterType, parameters [i].Type));
1383 if (invoke.ReturnType != typeof (void) && !CanAssign (invoke.ReturnType, body.Type))
1384 throw new ArgumentException (String.Format ("body type {0} can not be assigned to {1}", body.Type, invoke.ReturnType));
1387 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1389 return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1392 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1395 throw new ArgumentNullException ("body");
1397 var ps = parameters.ToReadOnlyCollection ();
1399 CheckLambda (typeof (TDelegate), body, ps);
1401 return new Expression<TDelegate> (body, ps);
1404 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1407 throw new ArgumentNullException ("body");
1408 if (parameters.Length > 4)
1409 throw new ArgumentException ("Too many parameters");
1411 return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1414 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1416 if (parameters == null)
1417 parameters = new ParameterExpression [0];
1419 if (return_type == typeof (void))
1420 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1422 var types = new Type [parameters.Length + 1];
1423 for (int i = 0; i < types.Length - 1; i++)
1424 types [i] = parameters [i].Type;
1426 types [types.Length - 1] = return_type;
1427 return GetFuncType (types);
1430 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1432 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1435 static LambdaExpression CreateExpressionOf (Type type, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1437 return (LambdaExpression) Activator.CreateInstance (
1438 typeof (Expression<>).MakeGenericType (type),
1439 NonPublicInstance, null, new object [] { body, parameters }, null);
1442 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1444 if (delegateType == null)
1445 throw new ArgumentNullException ("delegateType");
1447 throw new ArgumentNullException ("body");
1449 var ps = parameters.ToReadOnlyCollection ();
1451 CheckLambda (delegateType, body, ps);
1453 return CreateExpressionOf (delegateType, body, ps);
1456 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1458 return ListBind (member, initializers as IEnumerable<ElementInit>);
1461 static void CheckIsAssignableToIEnumerable (Type t)
1463 if (!t.IsAssignableTo (typeof (IEnumerable)))
1464 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
1467 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1470 throw new ArgumentNullException ("member");
1471 if (initializers == null)
1472 throw new ArgumentNullException ("initializers");
1474 var inits = initializers.ToReadOnlyCollection ();
1475 CheckForNull (inits, "initializers");
1477 member.OnFieldOrProperty (
1478 field => CheckIsAssignableToIEnumerable (field.FieldType),
1479 prop => CheckIsAssignableToIEnumerable (prop.PropertyType));
1481 return new MemberListBinding (member, inits);
1484 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1486 return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
1489 static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
1491 foreach (var t in collection)
1493 throw new ArgumentNullException (name);
1496 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1498 if (propertyAccessor == null)
1499 throw new ArgumentNullException ("propertyAccessor");
1500 if (initializers == null)
1501 throw new ArgumentNullException ("initializers");
1503 var inits = initializers.ToReadOnlyCollection ();
1504 CheckForNull (inits, "initializers");
1506 var prop = GetAssociatedProperty (propertyAccessor);
1508 throw new ArgumentException ("propertyAccessor");
1510 CheckIsAssignableToIEnumerable (prop.PropertyType);
1512 return new MemberListBinding (prop, inits);
1515 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1517 return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
1520 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1522 var inits = CheckListInit (newExpression, initializers);
1524 return new ListInitExpression (newExpression, inits);
1527 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1529 return ListInit (newExpression, initializers as IEnumerable<Expression>);
1532 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1534 var inits = CheckListInit (newExpression, initializers);
1536 var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
1537 if (add_method == null)
1538 throw new InvalidOperationException ("No suitable add method found");
1540 return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
1543 static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
1545 return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
1548 static MethodInfo GetAddMethod (Type type, Type arg)
1550 return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
1553 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1555 return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
1558 static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
1560 if (newExpression == null)
1561 throw new ArgumentNullException ("newExpression");
1562 if (initializers == null)
1563 throw new ArgumentNullException ("initializers");
1564 if (!newExpression.Type.IsAssignableTo (typeof (IEnumerable)))
1565 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1567 var inits = initializers.ToReadOnlyCollection ();
1568 if (inits.Count == 0)
1569 throw new ArgumentException ("Empty initializers");
1571 CheckForNull (inits, "initializers");
1576 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1578 var inits = CheckListInit (newExpression, initializers);
1580 if (addMethod != null) {
1581 if (addMethod.Name.ToLowerInvariant () != "add")
1582 throw new ArgumentException ("addMethod");
1584 var parameters = addMethod.GetParameters ();
1585 if (parameters.Length != 1)
1586 throw new ArgumentException ("addMethod");
1588 foreach (var expression in inits)
1589 if (!IsAssignableToParameterType (expression.Type, parameters [0]))
1590 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1593 if (addMethod == null)
1594 addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
1596 if (addMethod == null)
1597 throw new InvalidOperationException ("No suitable add method found");
1599 return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
1602 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1604 if (expression == null)
1605 throw new ArgumentNullException ("expression");
1607 throw new ArgumentNullException ("member");
1609 var field = member as FieldInfo;
1611 return Field (expression, field);
1613 var property = member as PropertyInfo;
1614 if (property != null)
1615 return Property (expression, property);
1617 throw new ArgumentException ("Member should either be a field or a property");
1620 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1622 return MakeUnary (unaryType, operand, type, null);
1625 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1627 switch (unaryType) {
1628 case ExpressionType.ArrayLength:
1629 return ArrayLength (operand);
1630 case ExpressionType.Convert:
1631 return Convert (operand, type, method);
1632 case ExpressionType.ConvertChecked:
1633 return ConvertChecked (operand, type, method);
1634 case ExpressionType.Negate:
1635 return Negate (operand, method);
1636 case ExpressionType.NegateChecked:
1637 return NegateChecked (operand, method);
1638 case ExpressionType.Not:
1639 return Not (operand, method);
1640 case ExpressionType.Quote:
1641 return Quote (operand);
1642 case ExpressionType.TypeAs:
1643 return TypeAs (operand, type);
1644 case ExpressionType.UnaryPlus:
1645 return UnaryPlus (operand, method);
1648 throw new ArgumentException ("MakeUnary expect an unary operator");
1651 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
1653 return MemberBind (member, bindings as IEnumerable<MemberBinding>);
1656 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
1659 throw new ArgumentNullException ("member");
1661 var type = member.OnFieldOrProperty (
1662 field => field.FieldType,
1663 prop => prop.PropertyType);
1665 return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
1668 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
1670 return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
1673 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
1675 if (propertyAccessor == null)
1676 throw new ArgumentNullException ("propertyAccessor");
1678 var bds = bindings.ToReadOnlyCollection ();
1679 CheckForNull (bds, "bindings");
1681 var prop = GetAssociatedProperty (propertyAccessor);
1683 throw new ArgumentException ("propertyAccessor");
1685 return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
1688 static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
1690 if (bindings == null)
1691 throw new ArgumentNullException ("bindings");
1693 var bds = bindings.ToReadOnlyCollection ();
1694 CheckForNull (bds, "bindings");
1696 foreach (var binding in bds)
1697 if (!type.IsAssignableTo (binding.Member.DeclaringType))
1698 throw new ArgumentException ("Type not assignable to member type");
1703 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
1705 return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
1708 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
1710 if (newExpression == null)
1711 throw new ArgumentNullException ("newExpression");
1713 return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
1716 public static UnaryExpression Negate (Expression expression)
1718 return Negate (expression, null);
1721 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1723 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1725 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1728 public static UnaryExpression NegateChecked (Expression expression)
1730 return NegateChecked (expression, null);
1733 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1735 method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1737 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1740 public static NewExpression New (ConstructorInfo constructor)
1742 if (constructor == null)
1743 throw new ArgumentNullException ("constructor");
1745 if (constructor.GetParameters ().Length > 0)
1746 throw new ArgumentException ("Constructor must be parameter less");
1748 return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
1751 public static NewExpression New (Type type)
1754 throw new ArgumentNullException ("type");
1756 CheckNotVoid (type);
1758 var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
1760 if (type.IsValueType)
1761 return new NewExpression (type, args);
1763 var ctor = type.GetConstructor (Type.EmptyTypes);
1765 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1767 return new NewExpression (ctor, args, null);
1770 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1772 return New (constructor, arguments as IEnumerable<Expression>);
1775 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1777 if (constructor == null)
1778 throw new ArgumentNullException ("constructor");
1780 var args = arguments.ToReadOnlyCollection ();
1782 CheckMethodArguments (constructor, args);
1784 return new NewExpression (constructor, args, null);
1787 static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
1789 var parameters = method.GetParameters ();
1791 if (arguments.Count != parameters.Length)
1792 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1794 for (int i = 0; i < parameters.Length; i++) {
1795 if (arguments [i] == null)
1796 throw new ArgumentNullException ("arguments");
1798 if (!IsAssignableToParameterType (arguments [i].Type, parameters [i]))
1799 throw new ArgumentException ("arguments");
1803 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1805 return New (constructor, arguments, members as IEnumerable<MemberInfo>);
1808 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1810 if (constructor == null)
1811 throw new ArgumentNullException ("constructor");
1813 var args = arguments.ToReadOnlyCollection ();
1814 var mmbs = members.ToReadOnlyCollection ();
1816 CheckForNull (args, "arguments");
1817 CheckForNull (mmbs, "members");
1819 CheckMethodArguments (constructor, args);
1821 if (args.Count != mmbs.Count)
1822 throw new ArgumentException ("Arguments count does not match members count");
1824 for (int i = 0; i < mmbs.Count; i++) {
1825 var member = mmbs [i];
1827 switch (member.MemberType) {
1828 case MemberTypes.Field:
1829 type = (member as FieldInfo).FieldType;
1831 case MemberTypes.Method:
1832 type = (member as MethodInfo).ReturnType;
1834 case MemberTypes.Property:
1835 var prop = member as PropertyInfo;
1836 if (prop.GetGetMethod (true) == null)
1837 throw new ArgumentException ("Property must have a getter");
1839 type = (member as PropertyInfo).PropertyType;
1842 throw new ArgumentException ("Member type not allowed");
1845 if (!args [i].Type.IsAssignableTo (type))
1846 throw new ArgumentException ("Argument type not assignable to member type");
1849 return new NewExpression (constructor, args, mmbs);
1852 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1854 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1857 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1860 throw new ArgumentNullException ("type");
1862 throw new ArgumentNullException ("bounds");
1864 CheckNotVoid (type);
1866 var array_bounds = bounds.ToReadOnlyCollection ();
1867 foreach (var expression in array_bounds)
1868 if (!IsInt (expression.Type))
1869 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1871 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1874 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1876 return NewArrayInit (type, initializers as IEnumerable<Expression>);
1879 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1882 throw new ArgumentNullException ("type");
1883 if (initializers == null)
1884 throw new ArgumentNullException ("initializers");
1886 CheckNotVoid (type);
1888 var inits = initializers.ToReadOnlyCollection ();
1890 foreach (var expression in inits) {
1891 if (expression == null)
1892 throw new ArgumentNullException ("initializers");
1894 if (!expression.Type.IsAssignableTo (type))
1895 throw new InvalidOperationException ();
1897 // TODO: Quote elements if type == typeof (Expression)
1900 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), inits);
1903 public static UnaryExpression Not (Expression expression)
1905 return Not (expression, null);
1908 public static UnaryExpression Not (Expression expression, MethodInfo method)
1910 Func<Type, bool> validator = type => IsIntOrBool (type);
1912 method = UnaryCoreCheck ("op_LogicalNot", expression, method, validator);
1915 method = UnaryCoreCheck ("op_OnesComplement", expression, method, validator);
1917 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1920 static void CheckNotVoid (Type type)
1922 if (type == typeof (void))
1923 throw new ArgumentException ("Type can't be void");
1926 public static ParameterExpression Parameter (Type type, string name)
1929 throw new ArgumentNullException ("type");
1931 CheckNotVoid (type);
1933 return new ParameterExpression (type, name);
1936 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1938 if (propertyAccessor == null)
1939 throw new ArgumentNullException ("propertyAccessor");
1941 if (!propertyAccessor.IsStatic) {
1942 if (expression == null)
1943 throw new ArgumentNullException ("expression");
1944 if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
1945 throw new ArgumentException ("expression");
1948 var prop = GetAssociatedProperty (propertyAccessor);
1950 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
1952 return new MemberExpression (expression, prop, prop.PropertyType);
1955 static PropertyInfo GetAssociatedProperty (MethodInfo method)
1957 foreach (var prop in method.DeclaringType.GetProperties (All)) {
1958 if (prop.GetGetMethod (true) == method)
1960 if (prop.GetSetMethod (true) == method)
1967 public static MemberExpression Property (Expression expression, PropertyInfo property)
1969 if (property == null)
1970 throw new ArgumentNullException ("property");
1972 var getter = property.GetGetMethod (true);
1974 throw new ArgumentException ("getter");
1976 if (!getter.IsStatic) {
1977 if (expression == null)
1978 throw new ArgumentNullException ("expression");
1979 if (!expression.Type.IsAssignableTo (property.DeclaringType))
1980 throw new ArgumentException ("expression");
1983 return new MemberExpression (expression, property, property.PropertyType);
1986 public static MemberExpression Property (Expression expression, string propertyName)
1988 if (expression == null)
1989 throw new ArgumentNullException ("expression");
1991 var prop = expression.Type.GetProperty (propertyName, AllInstance);
1993 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
1995 return new MemberExpression (expression, prop, prop.PropertyType);
1998 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
2000 if (expression == null)
2001 throw new ArgumentNullException ("expression");
2002 if (propertyOrFieldName == null)
2003 throw new ArgumentNullException ("propertyOrFieldName");
2005 var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
2007 return new MemberExpression (expression, prop, prop.PropertyType);
2009 var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
2011 return new MemberExpression (expression, field, field.FieldType);
2013 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
2016 public static UnaryExpression Quote (Expression expression)
2018 if (expression == null)
2019 throw new ArgumentNullException ("expression");
2021 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
2024 public static UnaryExpression TypeAs (Expression expression, Type type)
2026 if (expression == null)
2027 throw new ArgumentNullException ("expression");
2029 throw new ArgumentNullException ("type");
2030 if (type.IsValueType && !IsNullable (type))
2031 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
2033 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
2036 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
2038 if (expression == null)
2039 throw new ArgumentNullException ("expression");
2041 throw new ArgumentNullException ("type");
2043 CheckNotVoid (type);
2045 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
2048 public static UnaryExpression UnaryPlus (Expression expression)
2050 return UnaryPlus (expression, null);
2053 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
2055 method = UnaryCoreCheck ("op_UnaryPlus", expression, method, type => IsNumber (type));
2057 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
2060 static bool IsInt (Type t)
2062 return t == typeof (byte) || t == typeof (sbyte) ||
2063 t == typeof (short) || t == typeof (ushort) ||
2064 t == typeof (int) || t == typeof (uint) ||
2065 t == typeof (long) || t == typeof (ulong);
2068 static bool IsIntOrBool (Type t)
2070 return IsInt (t) || t == typeof (bool);
2073 static bool IsNumber (Type t)
2078 return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
2081 internal static bool IsNullable (Type type)
2083 return type.IsGenericInstanceOf (typeof (Nullable<>));
2086 static bool IsSignedNumber (Type t)
2088 return IsNumber (t) && !IsUnsigned (t);
2091 internal static bool IsUnsigned (Type t)
2095 return IsUnsigned (t.GetElementType ());
2098 return t == typeof (ushort) ||
2099 t == typeof (uint) ||
2100 t == typeof (ulong) ||
2105 // returns the T in a a Nullable<T> type.
2107 internal static Type GetNullableOf (Type type)
2109 return type.GetFirstGenericArgument ();
2112 internal static Type GetNotNullableOf (Type type)
2114 return IsNullable (type) ? GetNullableOf (type) : type;
2118 // This method must be overwritten by derived classes to
2119 // compile the expression
2121 internal virtual void Emit (EmitContext ec)
2123 throw new NotImplementedException ();