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, Expression expression)
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 (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
93 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method)
95 if (expression == null)
96 throw new ArgumentNullException ("expression");
99 if (method.ReturnType == typeof (void))
100 throw new ArgumentException ("Specified method must return a value", "method");
102 if (!method.IsStatic)
103 throw new ArgumentException ("Method must be static", "method");
105 var parameters = method.GetParameters ();
107 if (parameters.Length != 1)
108 throw new ArgumentException ("Must have only one parameters", "method");
110 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
111 throw new InvalidOperationException ("left-side argument type does not match left expression type");
115 if (IsNumber (expression.Type))
118 if (oper_name != null) {
119 method = GetUnaryOperator (oper_name, expression.Type, expression);
124 throw new InvalidOperationException (
125 String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
129 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
131 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
133 foreach (MethodInfo m in methods) {
134 if (m.Name != oper_name)
137 ParameterInfo [] pi = m.GetParameters ();
141 if (!pi [0].ParameterType.IsAssignableFrom (left.Type))
144 if (!pi [1].ParameterType.IsAssignableFrom (right.Type))
147 // Method has papers in order.
155 // Performs basic checks on the incoming expressions for binary expressions
156 // and any provided MethodInfo.
158 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
161 throw new ArgumentNullException ("left");
163 throw new ArgumentNullException ("right");
166 if (method.ReturnType == typeof (void))
167 throw new ArgumentException ("Specified method must return a value", "method");
169 if (!method.IsStatic)
170 throw new ArgumentException ("Method must be static", "method");
171 ParameterInfo [] pi = method.GetParameters ();
174 throw new ArgumentException ("Must have only two parameters", "method");
176 if (!pi [0].ParameterType.IsAssignableFrom (GetNotNullableOf (left.Type)))
177 throw new InvalidOperationException ("left-side argument type does not match left expression type");
179 if (!pi [1].ParameterType.IsAssignableFrom (GetNotNullableOf (right.Type)))
180 throw new InvalidOperationException ("right-side argument type does not match right expression type");
184 Type ltype = left.Type;
185 Type rtype = right.Type;
186 Type ultype = GetNotNullableOf (ltype);
187 Type urtype = GetNotNullableOf (rtype);
189 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
190 if (ultype == typeof (bool)) {
191 if (ultype == urtype && ltype == rtype)
196 // Use IsNumber to avoid expensive reflection.
197 if (IsNumber (ultype)){
198 if (ultype == urtype && ltype == rtype)
201 if (oper_name != null){
202 method = GetBinaryOperator (oper_name, rtype, left, right);
208 if (oper_name != null){
209 method = GetBinaryOperator (oper_name, ltype, left, right);
215 // == and != allow reference types without operators defined.
217 if (!ltype.IsValueType && !rtype.IsValueType &&
218 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
221 throw new InvalidOperationException (
222 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
227 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
228 // only ints and bools are allowed
230 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
233 throw new ArgumentNullException ("left");
235 throw new ArgumentNullException ("right");
237 if (method == null) {
238 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
239 if (left.Type == right.Type && IsIntOrBool (left.Type))
243 method = BinaryCoreCheck (oper_name, left, right, method);
244 if (method == null) {
245 // The check in BinaryCoreCheck allows a bit more than we do
246 // (floats and doubles). Catch this here
247 if (left.Type == typeof (double) || left.Type == typeof (float))
248 throw new InvalidOperationException ("Types not supported");
254 static Type GetResultType (Expression expression, MethodInfo method)
256 return method == null ? expression.Type : method.ReturnType;
259 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
263 if (method == null) {
264 if (IsNullable (left.Type)) {
265 if (!IsNullable (right.Type))
266 throw new InvalidOperationException ("Assertion, internal error: left is nullable, requires right to be as well");
278 return new BinaryExpression (et, GetResultType (left, method), left, right, is_lifted, is_lifted, method, null);
281 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
283 return new UnaryExpression (et, expression, GetResultType (expression, method), method);
286 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
289 Type ltype = left.Type;
290 Type rtype = right.Type;
291 bool lnullable = IsNullable (ltype);
292 bool rnullable = IsNullable (rtype);
295 // Implement the rules as described in "Expression.Equal" method.
296 if (method == null) {
297 if (!lnullable && !rnullable) {
300 result = typeof (bool);
301 } else if (lnullable && rnullable) {
303 result = liftToNull ? typeof(bool?) : typeof (bool);
305 throw new InvalidOperationException ("Internal error: this should have been caught in BinaryCoreCheck");
307 ParameterInfo [] pi = method.GetParameters ();
308 Type mltype = pi [0].ParameterType;
309 Type mrtype = pi [1].ParameterType;
311 if (ltype == mltype && rtype == mrtype) {
314 result = method.ReturnType;
315 } else if (ltype.IsValueType && rtype.IsValueType &&
316 ((lnullable && GetNullableOf (ltype) == mltype) ||
317 (rnullable && GetNullableOf (rtype) == mrtype))){
319 if (method.ReturnType == typeof(bool)){
320 result = liftToNull ? typeof(bool?) : typeof(bool);
323 // This behavior is not documented: what
324 // happens if the result is not typeof(bool), but
325 // the parameters are nullable: the result
326 // becomes nullable<returntype>
329 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
330 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
335 result = method.ReturnType;
339 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
345 public static BinaryExpression Add (Expression left, Expression right)
347 return Add (left, right, null);
350 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
352 method = BinaryCoreCheck ("op_Addition", left, right, method);
354 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
357 public static BinaryExpression AddChecked (Expression left, Expression right)
359 return AddChecked (left, right, null);
362 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
364 method = BinaryCoreCheck ("op_Addition", left, right, method);
366 // The check in BinaryCoreCheck allows a bit more than we do
367 // (byte, sbyte). Catch that here
368 if (method == null) {
369 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
370 throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
373 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
376 public static BinaryExpression Subtract (Expression left, Expression right)
378 return Subtract (left, right, null);
381 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
383 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
385 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
388 public static BinaryExpression SubtractChecked (Expression left, Expression right)
390 return SubtractChecked (left, right, null);
393 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
395 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
397 // The check in BinaryCoreCheck allows a bit more than we do
398 // (byte, sbyte). Catch that here
399 if (method == null) {
400 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
401 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
404 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
407 public static BinaryExpression Modulo (Expression left, Expression right)
409 return Modulo (left, right, null);
412 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
414 method = BinaryCoreCheck ("op_Modulus", left, right, method);
416 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
419 public static BinaryExpression Multiply (Expression left, Expression right)
421 return Multiply (left, right, null);
424 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
426 method = BinaryCoreCheck ("op_Multiply", left, right, method);
428 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
431 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
433 return MultiplyChecked (left, right, null);
436 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
438 method = BinaryCoreCheck ("op_Multiply", left, right, method);
440 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
443 public static BinaryExpression Divide (Expression left, Expression right)
445 return Divide (left, right, null);
448 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
450 method = BinaryCoreCheck ("op_Division", left, right, method);
452 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
455 public static BinaryExpression Power (Expression left, Expression right)
457 return Power (left, right, null);
460 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
462 method = BinaryCoreCheck (null, left, right, method);
464 if (left.Type != typeof (double))
465 throw new InvalidOperationException ("Power only supports double arguments");
467 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
473 public static BinaryExpression And (Expression left, Expression right)
475 return And (left, right, null);
478 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
480 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
482 return MakeSimpleBinary (ExpressionType.And, left, right, method);
485 public static BinaryExpression Or (Expression left, Expression right)
487 return Or (left, right, null);
490 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
492 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
494 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
497 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
499 return ExclusiveOr (left, right, null);
502 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
504 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
506 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
509 public static BinaryExpression LeftShift (Expression left, Expression right)
511 return LeftShift (left, right, null);
514 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
516 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
518 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
521 public static BinaryExpression RightShift (Expression left, Expression right)
523 return RightShift (left, right, null);
526 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
528 method = BinaryCoreCheck ("op_RightShift", left, right, method);
530 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
536 public static BinaryExpression AndAlso (Expression left, Expression right)
538 return AndAlso (left, right, null);
541 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
543 method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
545 return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
548 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
550 method = BinaryCoreCheck (oper, left, right, method);
552 if (method == null) {
553 if (GetNotNullableOf (left.Type) != typeof (bool))
554 throw new InvalidOperationException ("Only booleans are allowed");
556 // The method should have identical parameter and return types.
557 if (left.Type != right.Type || method.ReturnType != left.Type)
558 throw new ArgumentException ("left, right and return type must match");
564 public static BinaryExpression OrElse (Expression left, Expression right)
566 return OrElse (left, right, null);
569 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
571 method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
573 return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
579 public static BinaryExpression Equal (Expression left, Expression right)
581 return Equal (left, right, false, null);
584 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
586 method = BinaryCoreCheck ("op_Equality", left, right, method);
588 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
591 public static BinaryExpression NotEqual (Expression left, Expression right)
593 return NotEqual (left, right, false, null);
597 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
599 method = BinaryCoreCheck ("op_Inequality", left, right, method);
601 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
604 public static BinaryExpression GreaterThan (Expression left, Expression right)
606 return GreaterThan (left, right, false, null);
609 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
611 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
613 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
616 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
618 return GreaterThanOrEqual (left, right, false, null);
622 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
624 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
626 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
629 public static BinaryExpression LessThan (Expression left, Expression right)
631 return LessThan (left, right, false, null);
634 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
636 method = BinaryCoreCheck ("op_LessThan", left, right, method);
638 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
641 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
643 return LessThanOrEqual (left, right, false, null);
646 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
648 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
650 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
657 static void CheckArray (Expression array)
660 throw new ArgumentNullException ("array");
661 if (!array.Type.IsArray)
662 throw new ArgumentException ("The array argument must be of type array");
665 public static BinaryExpression ArrayIndex (Expression array, Expression index)
670 throw new ArgumentNullException ("index");
671 if (array.Type.GetArrayRank () != 1)
672 throw new ArgumentException ("The array argument must be a single dimensional array");
673 if (index.Type != typeof (int))
674 throw new ArgumentException ("The index must be of type int");
676 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
679 public static BinaryExpression Coalesce (Expression left, Expression right)
681 return Coalesce (left, right, null);
684 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
687 throw new ArgumentNullException ("left");
689 throw new ArgumentNullException ("right");
692 // First arg must ne nullable (either Nullable<T> or a reference type
694 if (left.Type.IsValueType && !IsNullable (left.Type))
695 throw new InvalidOperationException ("Left expression can never be null");
699 if (IsNullable (left.Type)){
700 Type lbase = GetNullableOf (left.Type);
702 if (!IsNullable (right.Type) && lbase.IsAssignableFrom (right.Type))
706 if (result == null && left.Type.IsAssignableFrom (right.Type))
710 if (IsNullable (left.Type) && right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
716 throw new ArgumentException ("Incompatible argument types");
719 // FIXME: What do we do with "conversion"?
721 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
725 // MakeBinary constructors
727 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
729 return MakeBinary (binaryType, left, right, false, null);
732 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
734 return MakeBinary (binaryType, left, right, liftToNull, method, null);
737 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
739 switch (binaryType) {
740 case ExpressionType.Add:
741 return Add (left, right, method);
742 case ExpressionType.AddChecked:
743 return AddChecked (left, right, method);
744 case ExpressionType.AndAlso:
745 return AndAlso (left, right);
746 case ExpressionType.Coalesce:
747 return Coalesce (left, right, conversion);
748 case ExpressionType.Divide:
749 return Divide (left, right, method);
750 case ExpressionType.Equal:
751 return Equal (left, right, liftToNull, method);
752 case ExpressionType.ExclusiveOr:
753 return ExclusiveOr (left, right, method);
754 case ExpressionType.GreaterThan:
755 return GreaterThan (left, right, liftToNull, method);
756 case ExpressionType.GreaterThanOrEqual:
757 return GreaterThanOrEqual (left, right, liftToNull, method);
758 case ExpressionType.LeftShift:
759 return LeftShift (left, right, method);
760 case ExpressionType.LessThan:
761 return LessThan (left, right, liftToNull, method);
762 case ExpressionType.LessThanOrEqual:
763 return LessThanOrEqual (left, right, liftToNull, method);
764 case ExpressionType.Modulo:
765 return Modulo (left, right, method);
766 case ExpressionType.Multiply:
767 return Multiply (left, right, method);
768 case ExpressionType.MultiplyChecked:
769 return MultiplyChecked (left, right, method);
770 case ExpressionType.NotEqual:
771 return NotEqual (left, right, liftToNull, method);
772 case ExpressionType.OrElse:
773 return OrElse (left, right);
774 case ExpressionType.Power:
775 return Power (left, right, method);
776 case ExpressionType.RightShift:
777 return RightShift (left, right, method);
778 case ExpressionType.Subtract:
779 return Subtract (left, right, method);
780 case ExpressionType.SubtractChecked:
781 return SubtractChecked (left, right, method);
782 case ExpressionType.And:
783 return And (left, right, method);
784 case ExpressionType.Or:
785 return Or (left, right, method);
788 throw new ArgumentException ("MakeBinary expect a binary node type");
793 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
795 return ArrayIndex (array, indexes as IEnumerable<Expression>);
798 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
803 throw new ArgumentNullException ("indexes");
805 var args = indexes.ToReadOnlyCollection ();
806 if (array.Type.GetArrayRank () != args.Count)
807 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
809 foreach (var arg in args)
810 if (arg.Type != typeof (int))
811 throw new ArgumentException ("The index must be of type int");
813 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
816 public static UnaryExpression ArrayLength (Expression array)
819 throw new ArgumentNullException ("array");
820 if (!array.Type.IsArray)
821 throw new ArgumentException ("The type of the expression must me Array");
822 if (array.Type.GetArrayRank () != 1)
823 throw new ArgumentException ("The array must be a single dimensional array");
825 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
828 public static MemberAssignment Bind (MemberInfo member, Expression expression)
831 throw new ArgumentNullException ("member");
832 if (expression == null)
833 throw new ArgumentNullException ("expression");
837 var prop = member as PropertyInfo;
838 if (prop != null && prop.GetSetMethod (true) != null)
839 type = prop.PropertyType;
841 var field = member as FieldInfo;
843 type = field.FieldType;
846 throw new ArgumentException ("member");
848 if (!type.IsAssignableFrom (expression.Type))
849 throw new ArgumentException ("member");
851 return new MemberAssignment (member, expression);
854 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
856 if (propertyAccessor == null)
857 throw new ArgumentNullException ("propertyAccessor");
858 if (expression == null)
859 throw new ArgumentNullException ("expression");
861 var prop = GetAssociatedProperty (propertyAccessor);
863 throw new ArgumentException ("propertyAccessor");
865 var setter = prop.GetSetMethod (true);
867 throw new ArgumentException ("setter");
869 if (!prop.PropertyType.IsAssignableFrom (expression.Type))
870 throw new ArgumentException ("member");
872 return new MemberAssignment (prop, expression);
875 public static MethodCallExpression Call (Expression instance, MethodInfo method)
877 return Call (instance, method, null as IEnumerable<Expression>);
880 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
882 return Call (null, method, arguments as IEnumerable<Expression>);
885 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
887 return Call (instance, method, arguments as IEnumerable<Expression>);
890 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
893 throw new ArgumentNullException ("method");
894 if (instance == null && !method.IsStatic)
895 throw new ArgumentNullException ("instance");
896 if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
897 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
899 var args = arguments.ToReadOnlyCollection ();
901 CheckMethodArguments (method, args);
903 return new MethodCallExpression (instance, method, args);
906 static Type [] CollectTypes (IEnumerable<Expression> expressions)
908 return (from arg in expressions select arg.Type).ToArray ();
911 static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
916 if (!method.IsGenericMethod && args == null)
919 if (args.Length == method.GetGenericArguments ().Length)
920 return method.MakeGenericMethod (args);
925 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
927 if (instance == null)
928 throw new ArgumentNullException ("instance");
929 if (methodName == null)
930 throw new ArgumentNullException ("methodName");
932 var method = GetGenericMethod (instance.Type, methodName, AllInstance,
933 CollectTypes (arguments), typeArguments);
935 var args = arguments.ToReadOnlyCollection ();
936 CheckMethodArguments (method, args);
938 return new MethodCallExpression (instance, method, args);
941 static MethodInfo GetGenericMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
943 var method = type.GetMethod (methodName, flags, null, parameterTypes, null);
944 method = TryMakeGeneric (method, argumentTypes);
948 throw new InvalidOperationException ("No such method");
951 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
954 throw new ArgumentNullException ("type");
955 if (methodName == null)
956 throw new ArgumentNullException ("methodName");
958 var method = GetGenericMethod (type, methodName, AllStatic,
959 CollectTypes (arguments), typeArguments);
961 var args = arguments.ToReadOnlyCollection ();
962 CheckMethodArguments (method, args);
964 return new MethodCallExpression (method, args);
967 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
970 throw new ArgumentNullException ("test");
972 throw new ArgumentNullException ("ifTrue");
974 throw new ArgumentNullException ("ifFalse");
975 if (test.Type != typeof (bool))
976 throw new ArgumentException ("Test expression should be of type bool");
977 if (ifTrue.Type != ifFalse.Type)
978 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
980 return new ConditionalExpression (test, ifTrue, ifFalse);
983 public static ConstantExpression Constant (object value)
986 return new ConstantExpression (null, typeof (object));
988 return Constant (value, value.GetType ());
991 public static ConstantExpression Constant (object value, Type type)
994 throw new ArgumentNullException ("type");
997 // value must be compatible with type, no conversions
1001 if (type.IsValueType && !IsNullable (type))
1002 throw new ArgumentException ();
1004 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
1005 throw new ArgumentException ();
1009 return new ConstantExpression (value, type);
1013 public static UnaryExpression Convert (Expression expression, Type type)
1015 throw new NotImplementedException ();
1019 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1021 throw new NotImplementedException ();
1025 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1027 throw new NotImplementedException ();
1031 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1033 throw new NotImplementedException ();
1036 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1038 return ElementInit (addMethod, arguments as IEnumerable<Expression>);
1041 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1043 if (addMethod == null)
1044 throw new ArgumentNullException ("addMethod");
1045 if (arguments == null)
1046 throw new ArgumentNullException ("arguments");
1047 if (addMethod.Name.ToLowerInvariant () != "add")
1048 throw new ArgumentException ("addMethod");
1049 if (addMethod.IsStatic)
1050 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1052 var args = arguments.ToReadOnlyCollection ();
1054 CheckMethodArguments (addMethod, args);
1056 return new ElementInit (addMethod, args);
1059 public static MemberExpression Field (Expression expression, FieldInfo field)
1062 throw new ArgumentNullException ("field");
1063 if (!field.IsStatic) {
1064 if (expression == null)
1065 throw new ArgumentNullException ("expression");
1066 if (!field.DeclaringType.IsAssignableFrom (expression.Type))
1067 throw new ArgumentException ("field");
1070 return new MemberExpression (expression, field, field.FieldType);
1073 public static MemberExpression Field (Expression expression, string fieldName)
1075 if (expression == null)
1076 throw new ArgumentNullException ("expression");
1078 var field = expression.Type.GetField (fieldName, AllInstance);
1080 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1082 return new MemberExpression (expression, field, field.FieldType);
1085 public static Type GetActionType (params Type [] typeArgs)
1087 if (typeArgs == null)
1088 throw new ArgumentNullException ("typeArgs");
1090 if (typeArgs.Length > 4)
1091 throw new ArgumentException ("No Action type of this arity");
1093 if (typeArgs.Length == 0)
1094 return typeof (Action);
1097 switch (typeArgs.Length) {
1099 action = typeof (Action<>);
1102 action = typeof (Action<,>);
1105 action = typeof (Action<,,>);
1108 action = typeof (Action<,,,>);
1112 return action.MakeGenericType (typeArgs);
1115 public static Type GetFuncType (params Type [] typeArgs)
1117 if (typeArgs == null)
1118 throw new ArgumentNullException ("typeArgs");
1120 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1121 throw new ArgumentException ("No Func type of this arity");
1124 switch (typeArgs.Length) {
1126 func = typeof (Func<>);
1129 func = typeof (Func<,>);
1132 func = typeof (Func<,,>);
1135 func = typeof (Func<,,,>);
1138 func = typeof (Func<,,,,>);
1142 return func.MakeGenericType (typeArgs);
1145 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1147 return Invoke (expression, arguments as IEnumerable<Expression>);
1150 static Type GetInvokableType (Type t)
1152 if (typeof (Delegate).IsAssignableFrom (t))
1155 return GetGenericType (t, typeof (Expression<>));
1158 static Type GetGenericType (Type t, Type def)
1163 if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
1166 return GetGenericType (t.BaseType, def);
1169 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1171 if (expression == null)
1172 throw new ArgumentNullException ("expression");
1174 var type = GetInvokableType (expression.Type);
1176 throw new ArgumentException ("The type of the expression is not invokable");
1178 var args = arguments.ToReadOnlyCollection ();
1179 CheckForNull (args, "arguments");
1181 var invoke = type.GetMethod ("Invoke");
1183 throw new ArgumentException ("expression");
1185 if (invoke.GetParameters ().Length != args.Count)
1186 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1188 CheckMethodArguments (invoke, args);
1190 return new InvocationExpression (expression, invoke.ReturnType, args);
1193 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1195 return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1198 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1201 throw new ArgumentNullException ("body");
1203 return new Expression<TDelegate> (body, parameters.ToReadOnlyCollection ());
1206 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1209 throw new ArgumentNullException ("body");
1210 if (parameters.Length > 4)
1211 throw new ArgumentException ("Too many parameters");
1213 return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1216 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1218 if (parameters == null)
1219 parameters = new ParameterExpression [0];
1221 if (return_type == typeof (void))
1222 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1224 var types = new Type [parameters.Length + 1];
1225 for (int i = 0; i < types.Length - 1; i++)
1226 types [i] = parameters [i].Type;
1228 types [types.Length - 1] = return_type;
1229 return GetFuncType (types);
1232 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1234 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1237 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1239 if (delegateType == null)
1240 throw new ArgumentNullException ("delegateType");
1242 throw new ArgumentNullException ("body");
1244 return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1247 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1249 return ListBind (member, initializers as IEnumerable<ElementInit>);
1252 static void CheckIsAssignableToIEnumerable (Type t)
1254 if (!typeof (IEnumerable).IsAssignableFrom (t))
1255 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
1258 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1261 throw new ArgumentNullException ("member");
1262 if (initializers == null)
1263 throw new ArgumentNullException ("initializers");
1265 var inits = initializers.ToReadOnlyCollection ();
1266 CheckForNull (inits, "initializers");
1268 switch (member.MemberType) {
1269 case MemberTypes.Field:
1270 CheckIsAssignableToIEnumerable ((member as FieldInfo).FieldType);
1272 case MemberTypes.Property:
1273 CheckIsAssignableToIEnumerable ((member as PropertyInfo).PropertyType);
1276 throw new ArgumentException ("member");
1279 return new MemberListBinding (member, inits);
1282 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1284 return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
1287 static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
1289 foreach (var t in collection)
1291 throw new ArgumentNullException (name);
1294 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1296 if (propertyAccessor == null)
1297 throw new ArgumentNullException ("propertyAccessor");
1298 if (initializers == null)
1299 throw new ArgumentNullException ("initializers");
1301 var inits = initializers.ToReadOnlyCollection ();
1302 CheckForNull (inits, "initializers");
1304 var prop = GetAssociatedProperty (propertyAccessor);
1306 throw new ArgumentException ("propertyAccessor");
1308 CheckIsAssignableToIEnumerable (prop.PropertyType);
1310 return new MemberListBinding (prop, inits);
1313 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1315 return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
1318 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1320 var inits = CheckListInit (newExpression, initializers);
1322 return new ListInitExpression (newExpression, inits);
1325 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1327 return ListInit (newExpression, initializers as IEnumerable<Expression>);
1330 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1332 var inits = CheckListInit (newExpression, initializers);
1334 var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
1335 if (add_method == null)
1336 throw new InvalidOperationException ("No suitable add method found");
1338 return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
1341 static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
1343 return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
1346 static MethodInfo GetAddMethod (Type type, Type arg)
1348 return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
1351 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1353 return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
1356 static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
1358 if (newExpression == null)
1359 throw new ArgumentNullException ("newExpression");
1360 if (initializers == null)
1361 throw new ArgumentNullException ("initializers");
1362 if (!typeof (IEnumerable).IsAssignableFrom (newExpression.Type))
1363 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1365 var inits = initializers.ToReadOnlyCollection ();
1366 if (inits.Count == 0)
1367 throw new ArgumentException ("Empty initializers");
1369 CheckForNull (inits, "initializers");
1374 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1376 var inits = CheckListInit (newExpression, initializers);
1378 if (addMethod != null) {
1379 if (addMethod.Name.ToLowerInvariant () != "add")
1380 throw new ArgumentException ("addMethod");
1382 var parameters = addMethod.GetParameters ();
1383 if (parameters.Length != 1)
1384 throw new ArgumentException ("addMethod");
1386 var type = parameters [0].ParameterType;
1388 foreach (var exp in inits)
1389 if (!type.IsAssignableFrom (exp.Type))
1390 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1393 if (addMethod == null)
1394 addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
1396 if (addMethod == null)
1397 throw new InvalidOperationException ("No suitable add method found");
1399 return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
1402 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1404 if (expression == null)
1405 throw new ArgumentNullException ("expression");
1407 throw new ArgumentNullException ("member");
1409 var field = member as FieldInfo;
1411 return Field (expression, field);
1413 var property = member as PropertyInfo;
1414 if (property != null)
1415 return Property (expression, property);
1417 throw new ArgumentException ("Member should either be a field or a property");
1420 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1422 return MakeUnary (unaryType, operand, type, null);
1425 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1427 switch (unaryType) {
1428 case ExpressionType.ArrayLength:
1429 return ArrayLength (operand);
1430 case ExpressionType.Convert:
1431 return Convert (operand, type, method);
1432 case ExpressionType.ConvertChecked:
1433 return ConvertChecked (operand, type, method);
1434 case ExpressionType.Negate:
1435 return Negate (operand, method);
1436 case ExpressionType.NegateChecked:
1437 return NegateChecked (operand, method);
1438 case ExpressionType.Not:
1439 return Not (operand, method);
1440 case ExpressionType.Quote:
1441 return Quote (operand);
1442 case ExpressionType.TypeAs:
1443 return TypeAs (operand, type);
1444 case ExpressionType.UnaryPlus:
1445 return UnaryPlus (operand, method);
1448 throw new ArgumentException ("MakeUnary expect an unary operator");
1451 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
1453 return MemberBind (member, bindings as IEnumerable<MemberBinding>);
1456 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
1459 throw new ArgumentNullException ("member");
1462 switch (member.MemberType) {
1463 case MemberTypes.Field:
1464 type = (member as FieldInfo).FieldType;
1466 case MemberTypes.Property:
1467 type = (member as PropertyInfo).PropertyType;
1470 throw new ArgumentException ("Member is neither a field or a property");
1473 return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
1476 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
1478 return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
1481 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
1483 if (propertyAccessor == null)
1484 throw new ArgumentNullException ("propertyAccessor");
1486 var bds = bindings.ToReadOnlyCollection ();
1487 CheckForNull (bds, "bindings");
1489 var prop = GetAssociatedProperty (propertyAccessor);
1491 throw new ArgumentException ("propertyAccessor");
1493 return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
1496 static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
1498 if (bindings == null)
1499 throw new ArgumentNullException ("bindings");
1501 var bds = bindings.ToReadOnlyCollection ();
1502 CheckForNull (bds, "bindings");
1504 foreach (var binding in bds)
1505 if (!binding.Member.DeclaringType.IsAssignableFrom (type))
1506 throw new ArgumentException ("Type not assignable to member type");
1511 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
1513 return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
1516 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
1518 if (newExpression == null)
1519 throw new ArgumentNullException ("newExpression");
1521 return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
1524 public static UnaryExpression Negate (Expression expression)
1526 return Negate (expression, null);
1529 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1531 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1533 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1536 public static UnaryExpression NegateChecked (Expression expression)
1538 return NegateChecked (expression, null);
1541 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1543 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1545 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1548 public static NewExpression New (ConstructorInfo constructor)
1550 if (constructor == null)
1551 throw new ArgumentNullException ("constructor");
1553 if (constructor.GetParameters ().Length > 0)
1554 throw new ArgumentException ("Constructor must be parameter less");
1556 return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
1559 public static NewExpression New (Type type)
1562 throw new ArgumentNullException ("type");
1564 var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
1566 if (type.IsValueType)
1567 return new NewExpression (type, args);
1569 var ctor = type.GetConstructor (Type.EmptyTypes);
1571 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1573 return new NewExpression (ctor, args, null);
1576 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1578 return New (constructor, arguments as IEnumerable<Expression>);
1581 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1583 if (constructor == null)
1584 throw new ArgumentNullException ("constructor");
1586 var args = arguments.ToReadOnlyCollection ();
1588 CheckMethodArguments (constructor, args);
1590 return new NewExpression (constructor, args, null);
1593 static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
1595 var parameters = method.GetParameters ();
1597 if (arguments.Count != parameters.Length)
1598 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1600 for (int i = 0; i < parameters.Length; i++) {
1601 if (arguments [i] == null)
1602 throw new ArgumentNullException ("arguments");
1604 if (!parameters [i].ParameterType.IsAssignableFrom (arguments [i].Type))
1605 throw new ArgumentException ("arguments");
1609 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1611 return New (constructor, arguments, members as IEnumerable<MemberInfo>);
1614 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1616 if (constructor == null)
1617 throw new ArgumentNullException ("constructor");
1619 var args = arguments.ToReadOnlyCollection ();
1620 var mmbs = members.ToReadOnlyCollection ();
1622 CheckForNull (args, "arguments");
1623 CheckForNull (mmbs, "members");
1625 CheckMethodArguments (constructor, args);
1627 if (args.Count != mmbs.Count)
1628 throw new ArgumentException ("Arguments count does not match members count");
1630 for (int i = 0; i < mmbs.Count; i++) {
1631 var member = mmbs [i];
1633 switch (member.MemberType) {
1634 case MemberTypes.Field:
1635 type = (member as FieldInfo).FieldType;
1637 case MemberTypes.Method:
1638 type = (member as MethodInfo).ReturnType;
1640 case MemberTypes.Property:
1641 var prop = member as PropertyInfo;
1642 if (prop.GetGetMethod (true) == null)
1643 throw new ArgumentException ("Property must have a getter");
1645 type = (member as PropertyInfo).PropertyType;
1648 throw new ArgumentException ("Member type not allowed");
1651 if (!type.IsAssignableFrom (args [i].Type))
1652 throw new ArgumentException ("Argument type not assignable to member type");
1655 return new NewExpression (constructor, args, mmbs);
1658 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1660 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1663 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1666 throw new ArgumentNullException ("type");
1668 throw new ArgumentNullException ("bounds");
1670 var array_bounds = bounds.ToReadOnlyCollection ();
1671 foreach (var expression in array_bounds)
1672 if (!IsInt (expression.Type))
1673 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1675 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1678 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1680 return NewArrayInit (type, initializers as IEnumerable<Expression>);
1683 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1686 throw new ArgumentNullException ("type");
1687 if (initializers == null)
1688 throw new ArgumentNullException ("initializers");
1690 var array_initializers = initializers.ToReadOnlyCollection ();
1692 foreach (var expression in initializers) {
1693 if (expression == null)
1694 throw new ArgumentNullException ("initializers");
1696 if (!type.IsAssignableFrom (expression.Type))
1697 throw new InvalidOperationException ();
1699 // TODO: Quote elements if type == typeof (Expression)
1702 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
1705 public static UnaryExpression Not (Expression expression)
1707 return Not (expression, null);
1710 public static UnaryExpression Not (Expression expression, MethodInfo method)
1712 method = UnaryCoreCheck ("op_LogicalNot", expression, method);
1714 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1717 public static ParameterExpression Parameter (Type type, string name)
1720 throw new ArgumentNullException ("type");
1722 return new ParameterExpression (type, name);
1725 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1727 if (propertyAccessor == null)
1728 throw new ArgumentNullException ("propertyAccessor");
1730 if (!propertyAccessor.IsStatic) {
1731 if (expression == null)
1732 throw new ArgumentNullException ("expression");
1733 if (!propertyAccessor.DeclaringType.IsAssignableFrom (expression.Type))
1734 throw new ArgumentException ("expression");
1737 var prop = GetAssociatedProperty (propertyAccessor);
1739 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
1741 return new MemberExpression (expression, prop, prop.PropertyType);
1744 static PropertyInfo GetAssociatedProperty (MethodInfo method)
1746 foreach (var prop in method.DeclaringType.GetProperties (All)) {
1747 if (prop.GetGetMethod (true) == method)
1749 if (prop.GetSetMethod (true) == method)
1756 public static MemberExpression Property (Expression expression, PropertyInfo property)
1758 if (property == null)
1759 throw new ArgumentNullException ("property");
1761 var getter = property.GetGetMethod (true);
1763 throw new ArgumentException ("getter");
1765 if (!getter.IsStatic) {
1766 if (expression == null)
1767 throw new ArgumentNullException ("expression");
1768 if (!property.DeclaringType.IsAssignableFrom (expression.Type))
1769 throw new ArgumentException ("expression");
1772 return new MemberExpression (expression, property, property.PropertyType);
1775 public static MemberExpression Property (Expression expression, string propertyName)
1777 if (expression == null)
1778 throw new ArgumentNullException ("expression");
1780 var prop = expression.Type.GetProperty (propertyName, AllInstance);
1782 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
1784 return new MemberExpression (expression, prop, prop.PropertyType);
1787 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1789 if (expression == null)
1790 throw new ArgumentNullException ("expression");
1791 if (propertyOrFieldName == null)
1792 throw new ArgumentNullException ("propertyOrFieldName");
1794 var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
1796 return new MemberExpression (expression, prop, prop.PropertyType);
1798 var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
1800 return new MemberExpression (expression, field, field.FieldType);
1802 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
1805 public static UnaryExpression Quote (Expression expression)
1807 if (expression == null)
1808 throw new ArgumentNullException ("expression");
1810 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1813 public static UnaryExpression TypeAs (Expression expression, Type type)
1815 if (expression == null)
1816 throw new ArgumentNullException ("expression");
1818 throw new ArgumentNullException ("type");
1819 if (type.IsValueType && !IsNullable (type))
1820 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1822 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1825 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1827 if (expression == null)
1828 throw new ArgumentNullException ("expression");
1830 throw new ArgumentNullException ("type");
1832 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1835 public static UnaryExpression UnaryPlus (Expression expression)
1837 return UnaryPlus (expression, null);
1840 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1842 method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
1844 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1847 static bool IsInt (Type t)
1849 return t == typeof (byte) || t == typeof (sbyte) ||
1850 t == typeof (short) || t == typeof (ushort) ||
1851 t == typeof (int) || t == typeof (uint) ||
1852 t == typeof (long) || t == typeof (ulong);
1855 static bool IsIntOrBool (Type t)
1857 return IsInt (t) || t == typeof (bool);
1860 static bool IsNumber (Type t)
1865 return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
1868 internal static bool IsNullable (Type type)
1870 return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1873 internal static bool IsUnsigned (Type t)
1876 return IsUnsigned (t.GetElementType ());
1878 return t == typeof (ushort) ||
1879 t == typeof (uint) ||
1880 t == typeof (ulong) ||
1885 // returns the T in a a Nullable<T> type.
1887 internal static Type GetNullableOf (Type type)
1889 return type.GetGenericArguments () [0];
1892 internal static Type GetNotNullableOf (Type type)
1894 return IsNullable (type) ? GetNullableOf (type) : type;
1898 // This method must be overwritten by derived classes to
1899 // compile the expression
1901 internal abstract void Emit (EmitContext ec);