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.Generic;
32 using System.Collections.ObjectModel;
34 using System.Reflection;
36 namespace System.Linq.Expressions {
38 public abstract class Expression {
40 ExpressionType node_type;
43 static BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
44 static BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
45 static BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
46 static BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
47 static BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
49 public ExpressionType NodeType {
50 get { return node_type; }
57 protected Expression (ExpressionType node_type, Type type)
59 this.node_type = node_type;
63 public override string ToString ()
65 return ExpressionPrinter.ToString (this);
68 static void CheckMethod (MethodInfo m)
72 #region Binary Expressions
73 static bool IsInt (Type t)
75 return t == typeof (byte) || t == typeof (sbyte) ||
76 t == typeof (short) || t == typeof (ushort) ||
77 t == typeof (int) || t == typeof (uint) ||
78 t == typeof (long) || t == typeof (ulong);
81 static bool IsNumber (Type t)
86 return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
89 static MethodInfo GetUnaryOperator (string oper_name, Type on_type, Expression expression)
91 var methods = on_type.GetMethods (PublicStatic);
93 foreach (var method in methods) {
94 if (method.Name != oper_name)
97 var parameters = method.GetParameters ();
98 if (parameters.Length != 1)
101 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
110 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method)
112 if (expression == null)
113 throw new ArgumentNullException ("expression");
115 if (method != null) {
116 if (method.ReturnType == typeof (void))
117 throw new ArgumentException ("Specified method must return a value", "method");
119 if (!method.IsStatic)
120 throw new ArgumentException ("Method must be static", "method");
122 var parameters = method.GetParameters ();
124 if (parameters.Length != 1)
125 throw new ArgumentException ("Must have only one parameters", "method");
127 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
128 throw new InvalidOperationException ("left-side argument type does not match left expression type");
132 if (IsNumber (expression.Type))
135 if (oper_name != null) {
136 method = GetUnaryOperator (oper_name, expression.Type, expression);
141 throw new InvalidOperationException (
142 String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
146 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
148 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
150 foreach (MethodInfo m in methods){
151 if (m.Name != oper_name)
154 ParameterInfo [] pi = m.GetParameters ();
158 if (!pi [0].ParameterType.IsAssignableFrom (left.Type))
161 if (!pi [1].ParameterType.IsAssignableFrom (right.Type))
164 // Method has papers in order.
172 // Performs basic checks on the incoming expressions for binary expressions
173 // and any provided MethodInfo.
175 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
178 throw new ArgumentNullException ("left");
180 throw new ArgumentNullException ("right");
183 if (method.ReturnType == typeof (void))
184 throw new ArgumentException ("Specified method must return a value", "method");
186 if (!method.IsStatic)
187 throw new ArgumentException ("Method must be static", "method");
188 ParameterInfo [] pi = method.GetParameters ();
191 throw new ArgumentException ("Must have only two parameters", "method");
193 Type ltype = left.Type.IsValueType && IsNullable (left.Type) ? GetNullableOf(left.Type) : left.Type;
194 Type rtype = left.Type.IsValueType && IsNullable (right.Type) ? GetNullableOf(right.Type) :right.Type;
196 if (ltype != pi [0].ParameterType)
197 throw new InvalidOperationException ("left-side argument type does not match left expression type");
199 if (rtype != pi [1].ParameterType)
200 throw new InvalidOperationException ("right-side argument type does not match right expression type");
204 Type ltype = left.Type;
205 Type rtype = right.Type;
206 Type ultype = left.Type;
207 Type urtype = right.Type;
209 if (IsNullable (ltype))
210 ultype = GetNullableOf (ltype);
212 if (IsNullable (rtype))
213 urtype = GetNullableOf (rtype);
215 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd"){
216 if (ultype == typeof (bool)){
217 if (ultype == urtype && ltype == rtype)
222 // Use IsNumber to avoid expensive reflection.
223 if (IsNumber (ultype)){
224 if (ultype == urtype && ltype == rtype)
227 if (oper_name != null){
228 method = GetBinaryOperator (oper_name, rtype, left, right);
234 if (oper_name != null){
235 method = GetBinaryOperator (oper_name, ltype, left, right);
241 // == and != allow reference types without operators defined.
243 if (!ltype.IsValueType && !rtype.IsValueType &&
244 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
247 throw new InvalidOperationException (
248 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
253 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
254 // only ints and bools are allowed
256 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
259 throw new ArgumentNullException ("left");
261 throw new ArgumentNullException ("right");
264 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
265 if (left.Type == right.Type && (left.Type == typeof (bool) || IsInt (left.Type)))
269 method = BinaryCoreCheck (oper_name, left, right, method);
272 // The check in BinaryCoreCheck allows a bit more than we do
273 // (floats and doubles). Catch this here
275 if (left.Type == typeof(double) || left.Type == typeof(float))
276 throw new InvalidOperationException ("Types not supported");
282 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
284 Type result = method == null ? left.Type : method.ReturnType;
288 if (IsNullable (left.Type)){
289 if (!IsNullable (right.Type))
290 throw new Exception ("Assertion, internal error: left is nullable, requires right to be as well");
301 return new BinaryExpression (et, result, left, right, false, is_lifted, method, null);
304 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
306 Type result = method == null ? expression.Type : method.ReturnType;
308 return new UnaryExpression (et, expression, result, method);
311 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
314 Type ltype = left.Type;
315 Type rtype = right.Type;
316 bool lnullable = IsNullable (ltype);
317 bool rnullable = IsNullable (rtype);
321 // Implement the rules as described in "Expression.Equal" method.
324 if (lnullable == false && rnullable == false){
326 result = typeof (bool);
327 } else if (lnullable && rnullable){
329 result = liftToNull ? typeof(bool?) : typeof (bool);
331 throw new Exception ("Internal error: this should have been caught in BinaryCoreCheck");
333 ParameterInfo [] pi = method.GetParameters ();
334 Type mltype = pi [0].ParameterType;
335 Type mrtype = pi [1].ParameterType;
337 if (ltype == mltype && rtype == mrtype){
339 result = method.ReturnType;
341 else if (ltype.IsValueType && rtype.IsValueType &&
342 ((lnullable && GetNullableOf (ltype) == mltype) ||
343 (rnullable && GetNullableOf (rtype) == mrtype))){
345 if (method.ReturnType == typeof(bool)){
346 result = liftToNull ? typeof(bool?) : typeof(bool);
349 // This behavior is not documented: what
350 // happens if the result is not typeof(bool), but
351 // the parameters are nullable: the result
352 // becomes nullable<returntype>
355 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
356 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
357 //Type.GetType ("System.Nullable`1[" + method.ReturnType.ToString () + "]");
361 result = method.ReturnType;
365 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
371 public static BinaryExpression Add (Expression left, Expression right)
373 return Add (left, right, null);
376 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
378 method = BinaryCoreCheck ("op_Addition", left, right, method);
380 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
383 public static BinaryExpression AddChecked (Expression left, Expression right)
385 return AddChecked (left, right, null);
388 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
390 method = BinaryCoreCheck ("op_Addition", left, right, method);
393 // The check in BinaryCoreCheck allows a bit more than we do
394 // (byte, sbyte). Catch that here
398 Type ltype = left.Type;
400 if (ltype == typeof (byte) || ltype == typeof (sbyte))
401 throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
404 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
407 public static BinaryExpression Subtract (Expression left, Expression right)
409 return Subtract (left, right, null);
412 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
414 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
415 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
418 public static BinaryExpression SubtractChecked (Expression left, Expression right)
420 return SubtractChecked (left, right, null);
423 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
425 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
428 // The check in BinaryCoreCheck allows a bit more than we do
429 // (byte, sbyte). Catch that here
433 Type ltype = left.Type;
435 if (ltype == typeof (byte) || ltype == typeof (sbyte))
436 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, false, 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 (left.Type != typeof (bool))
588 throw new InvalidOperationException ("Only booleans are allowed");
590 // The method should have identical parameter and return types.
592 if (left.Type != right.Type || method.ReturnType != left.Type)
593 throw new ArgumentException ("left, right and return type must match");
599 public static BinaryExpression OrElse (Expression left, Expression right)
601 return OrElse (left, right, null);
604 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
606 method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
608 return MakeBoolBinary (ExpressionType.OrElse, left, right, false, method);
614 public static BinaryExpression Equal (Expression left, Expression right)
616 return Equal (left, right, false, null);
619 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
621 method = BinaryCoreCheck ("op_Equality", left, right, method);
623 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
626 public static BinaryExpression NotEqual (Expression left, Expression right)
628 return NotEqual (left, right, false, null);
632 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
634 method = BinaryCoreCheck ("op_Inequality", left, right, method);
636 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
639 public static BinaryExpression GreaterThan (Expression left, Expression right)
641 return GreaterThan (left, right, false, null);
644 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
646 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
648 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
651 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
653 return GreaterThanOrEqual (left, right, false, null);
657 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
659 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
661 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
664 public static BinaryExpression LessThan (Expression left, Expression right)
666 return LessThan (left, right, false, null);
669 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
671 method = BinaryCoreCheck ("op_LessThan", left, right, method);
673 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
676 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
678 return LessThanOrEqual (left, right, false, null);
681 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
683 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
685 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
692 static void ArrayCheck (Expression array)
695 throw new ArgumentNullException ("array");
696 if (!array.Type.IsArray)
697 throw new ArgumentException ("The array argument must be of type array");
700 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) && lbase.IsAssignableFrom (right.Type))
740 if (result == null && left.Type.IsAssignableFrom (right.Type))
744 if (IsNullable (left.Type) && right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
750 throw new ArgumentException ("Incompatible argument types");
753 // FIXME: What do we do with "conversion"?
755 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
759 // MakeBinary constructors
761 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
763 return MakeBinary (binaryType, left, right, false, null);
766 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
768 return MakeBinary (binaryType, left, right, liftToNull, method, null);
771 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
773 switch (binaryType) {
774 case ExpressionType.Add:
775 return Add (left, right, method);
776 case ExpressionType.AddChecked:
777 return AddChecked (left, right, method);
778 case ExpressionType.AndAlso:
779 return AndAlso (left, right);
780 case ExpressionType.Coalesce:
781 return Coalesce (left, right, conversion);
782 case ExpressionType.Divide:
783 return Divide (left, right, method);
784 case ExpressionType.Equal:
785 return Equal (left, right, liftToNull, method);
786 case ExpressionType.ExclusiveOr:
787 return ExclusiveOr (left, right, method);
788 case ExpressionType.GreaterThan:
789 return GreaterThan (left, right, liftToNull, method);
790 case ExpressionType.GreaterThanOrEqual:
791 return GreaterThanOrEqual (left, right, liftToNull, method);
792 case ExpressionType.LeftShift:
793 return LeftShift (left, right, method);
794 case ExpressionType.LessThan:
795 return LessThan (left, right, liftToNull, method);
796 case ExpressionType.LessThanOrEqual:
797 return LessThanOrEqual (left, right, liftToNull, method);
798 case ExpressionType.Modulo:
799 return Modulo (left, right, method);
800 case ExpressionType.Multiply:
801 return Multiply (left, right, method);
802 case ExpressionType.MultiplyChecked:
803 return MultiplyChecked (left, right, method);
804 case ExpressionType.NotEqual:
805 return NotEqual (left, right, liftToNull, method);
806 case ExpressionType.OrElse:
807 return OrElse (left, right);
808 case ExpressionType.Power:
809 return Power (left, right, method);
810 case ExpressionType.RightShift:
811 return RightShift (left, right, method);
812 case ExpressionType.Subtract:
813 return Subtract (left, right, method);
814 case ExpressionType.SubtractChecked:
815 return SubtractChecked (left, right, method);
816 case ExpressionType.And:
817 return And (left, right, method);
818 case ExpressionType.Or:
819 return Or (left, right, method);
822 throw new ArgumentException ("MakeBinary expect a binary node type");
827 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
829 return ArrayIndex (array, indexes as IEnumerable<Expression>);
832 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
837 throw new ArgumentNullException ("indexes");
839 var args = indexes.ToReadOnlyCollection ();
840 if (array.Type.GetArrayRank () != args.Count)
841 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
843 foreach (var arg in args)
844 if (arg.Type != typeof (int))
845 throw new ArgumentException ("The index must be of type int");
847 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
850 public static UnaryExpression ArrayLength (Expression array)
853 throw new ArgumentNullException ("array");
854 if (!array.Type.IsArray)
855 throw new ArgumentException ("The type of the expression must me Array");
856 if (array.Type.GetArrayRank () != 1)
857 throw new ArgumentException ("The array must be a single dimensional array");
859 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
862 public static MemberAssignment Bind (MemberInfo member, Expression expression)
865 throw new ArgumentNullException ("member");
866 if (expression == null)
867 throw new ArgumentNullException ("expression");
871 var prop = member as PropertyInfo;
872 if (prop != null && prop.GetSetMethod (true) != null)
873 type = prop.PropertyType;
875 var field = member as FieldInfo;
877 type = field.FieldType;
880 throw new ArgumentException ("member");
882 if (!type.IsAssignableFrom (expression.Type))
883 throw new ArgumentException ("member");
885 return new MemberAssignment (member, expression);
888 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
890 if (propertyAccessor == null)
891 throw new ArgumentNullException ("propertyAccessor");
892 if (expression == null)
893 throw new ArgumentNullException ("expression");
895 var prop = GetAssociatedProperty (propertyAccessor);
897 throw new ArgumentException ("propertyAccessor");
899 var setter = prop.GetSetMethod (true);
901 throw new ArgumentException ("setter");
903 if (!prop.PropertyType.IsAssignableFrom (expression.Type))
904 throw new ArgumentException ("member");
906 return new MemberAssignment (prop, expression);
909 public static MethodCallExpression Call (Expression instance, MethodInfo method)
911 return Call (instance, method, null as IEnumerable<Expression>);
914 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
916 return Call (null, method, arguments as IEnumerable<Expression>);
919 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
921 return Call (instance, method, arguments as IEnumerable<Expression>);
924 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
927 throw new ArgumentNullException ("method");
928 if (instance == null && !method.IsStatic)
929 throw new ArgumentNullException ("instance");
930 if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
931 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
933 var args = arguments.ToReadOnlyCollection ();
935 CheckMethodArguments (method, args);
937 return new MethodCallExpression (instance, method, args);
940 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
942 if (instance == null)
943 throw new ArgumentNullException ("instance");
944 if (methodName == null)
945 throw new ArgumentNullException ("methodName");
947 if (typeArguments == null)
948 typeArguments = new Type [0];
950 var method = instance.Type.GetMethod (methodName, AllInstance, null, typeArguments, null);
952 throw new InvalidOperationException ("No such method");
954 var args = arguments.ToReadOnlyCollection ();
955 if (typeArguments.Length != args.Count)
956 throw new InvalidOperationException ("Argument count doesn't match parameters length");
958 return new MethodCallExpression (instance, method, args);
961 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
964 throw new ArgumentNullException ("type");
965 if (methodName == null)
966 throw new ArgumentNullException ("methodName");
968 if (typeArguments == null)
969 typeArguments = new Type [0];
971 var method = type.GetMethod (methodName, AllStatic, null, typeArguments, null);
973 throw new InvalidOperationException ("No such method");
975 var args = arguments.ToReadOnlyCollection ();
976 if (typeArguments.Length != args.Count)
977 throw new InvalidOperationException ("Argument count doesn't match parameters length");
979 return new MethodCallExpression (method, args);
982 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
985 throw new ArgumentNullException ("test");
987 throw new ArgumentNullException ("ifTrue");
989 throw new ArgumentNullException ("ifFalse");
990 if (test.Type != typeof (bool))
991 throw new ArgumentException ("Test expression should be of type bool");
992 if (ifTrue.Type != ifFalse.Type)
993 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
995 return new ConditionalExpression (test, ifTrue, ifFalse);
998 public static ConstantExpression Constant (object value)
1001 return new ConstantExpression (null, typeof (object));
1003 return Constant (value, value.GetType ());
1006 public static ConstantExpression Constant (object value, Type type)
1009 throw new ArgumentNullException ("type");
1012 // value must be compatible with type, no conversions
1016 if (type.IsValueType && !IsNullable (type))
1017 throw new ArgumentException ();
1019 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
1020 throw new ArgumentException ();
1024 return new ConstantExpression (value, type);
1028 public static UnaryExpression Convert (Expression expression, Type type)
1030 throw new NotImplementedException ();
1034 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1036 throw new NotImplementedException ();
1040 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1042 throw new NotImplementedException ();
1046 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1048 throw new NotImplementedException ();
1052 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1054 throw new NotImplementedException ();
1058 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1060 throw new NotImplementedException ();
1063 public static MemberExpression Field (Expression expression, FieldInfo field)
1066 throw new ArgumentNullException ("field");
1067 if (!field.IsStatic) {
1068 if (expression == null)
1069 throw new ArgumentNullException ("expression");
1070 if (!field.DeclaringType.IsAssignableFrom (expression.Type))
1071 throw new ArgumentException ("field");
1074 return new MemberExpression (expression, field, field.FieldType);
1077 public static MemberExpression Field (Expression expression, string fieldName)
1079 if (expression == null)
1080 throw new ArgumentNullException ("expression");
1082 var field = expression.Type.GetField (fieldName, AllInstance);
1084 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1086 return new MemberExpression (expression, field, field.FieldType);
1089 public static Type GetActionType (params Type [] typeArgs)
1091 if (typeArgs == null)
1092 throw new ArgumentNullException ("typeArgs");
1094 if (typeArgs.Length > 4)
1095 throw new ArgumentException ("No Action type of this arity");
1097 if (typeArgs.Length == 0)
1098 return typeof (Action);
1101 switch (typeArgs.Length) {
1103 action = typeof (Action<>);
1106 action = typeof (Action<,>);
1109 action = typeof (Action<,,>);
1112 action = typeof (Action<,,,>);
1116 return action.MakeGenericType (typeArgs);
1119 public static Type GetFuncType (params Type [] typeArgs)
1121 if (typeArgs == null)
1122 throw new ArgumentNullException ("typeArgs");
1124 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1125 throw new ArgumentException ("No Func type of this arity");
1128 switch (typeArgs.Length) {
1130 func = typeof (Func<>);
1133 func = typeof (Func<,>);
1136 func = typeof (Func<,,>);
1139 func = typeof (Func<,,,>);
1142 func = typeof (Func<,,,,>);
1146 return func.MakeGenericType (typeArgs);
1150 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1152 throw new NotImplementedException ();
1156 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1158 throw new NotImplementedException ();
1161 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1163 return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1166 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1169 throw new ArgumentNullException ("body");
1171 return new Expression<TDelegate> (body, parameters.ToReadOnlyCollection ());
1174 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1177 throw new ArgumentNullException ("body");
1178 if (parameters.Length > 4)
1179 throw new ArgumentException ("Too many parameters");
1181 return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1184 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1186 if (parameters == null)
1187 parameters = new ParameterExpression [0];
1189 if (return_type == typeof (void))
1190 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1192 var types = new Type [parameters.Length + 1];
1193 for (int i = 0; i < types.Length - 1; i++)
1194 types [i] = parameters [i].Type;
1196 types [types.Length - 1] = return_type;
1197 return GetFuncType (types);
1200 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1202 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1205 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1207 if (delegateType == null)
1208 throw new ArgumentNullException ("delegateType");
1210 throw new ArgumentNullException ("body");
1212 return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1215 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1217 throw new NotImplementedException ();
1221 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1223 throw new NotImplementedException ();
1227 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1229 throw new NotImplementedException ();
1233 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1235 throw new NotImplementedException ();
1239 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1241 throw new NotImplementedException ();
1245 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1247 throw new NotImplementedException ();
1251 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1253 throw new NotImplementedException ();
1257 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1259 throw new NotImplementedException ();
1263 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1265 throw new NotImplementedException ();
1269 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1271 throw new NotImplementedException ();
1274 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1276 if (expression == null)
1277 throw new ArgumentNullException ("expression");
1279 throw new ArgumentNullException ("member");
1281 var field = member as FieldInfo;
1283 return Field (expression, field);
1285 var property = member as PropertyInfo;
1286 if (property != null)
1287 return Property (expression, property);
1289 throw new ArgumentException ("Member should either be a field or a property");
1292 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1294 return MakeUnary (unaryType, operand, type, null);
1297 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1299 switch (unaryType) {
1300 case ExpressionType.ArrayLength:
1301 return ArrayLength (operand);
1302 case ExpressionType.Convert:
1303 return Convert (operand, type, method);
1304 case ExpressionType.ConvertChecked:
1305 return ConvertChecked (operand, type, method);
1306 case ExpressionType.Negate:
1307 return Negate (operand, method);
1308 case ExpressionType.NegateChecked:
1309 return NegateChecked (operand, method);
1310 case ExpressionType.Not:
1311 return Not (operand, method);
1312 case ExpressionType.Quote:
1313 return Quote (operand);
1314 case ExpressionType.TypeAs:
1315 return TypeAs (operand, type);
1316 case ExpressionType.UnaryPlus:
1317 return UnaryPlus (operand, method);
1320 throw new ArgumentException ("MakeUnary expect an unary operator");
1324 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] binding)
1326 throw new NotImplementedException ();
1330 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> binding)
1332 throw new NotImplementedException ();
1336 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] binding)
1338 throw new NotImplementedException ();
1342 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> binding)
1344 throw new NotImplementedException ();
1348 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] binding)
1350 throw new NotImplementedException ();
1354 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> binding)
1356 throw new NotImplementedException ();
1359 public static UnaryExpression Negate (Expression expression)
1361 return Negate (expression, null);
1364 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1366 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1368 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1371 public static UnaryExpression NegateChecked (Expression expression)
1373 return NegateChecked (expression, null);
1376 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1378 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1380 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1383 public static NewExpression New (ConstructorInfo constructor)
1385 if (constructor == null)
1386 throw new ArgumentNullException ("constructor");
1388 if (constructor.GetParameters ().Length > 0)
1389 throw new ArgumentException ("Constructor must be parameter less");
1391 return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> (), null);
1394 public static NewExpression New (Type type)
1397 throw new ArgumentNullException ("type");
1399 if (type.GetConstructor (Type.EmptyTypes) == null)
1400 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1402 return new NewExpression (type, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> ());
1405 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1407 return New (constructor, arguments as IEnumerable<Expression>);
1410 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1412 if (constructor == null)
1413 throw new ArgumentNullException ("constructor");
1415 var args = arguments.ToReadOnlyCollection ();
1417 CheckMethodArguments (constructor, args);
1419 return new NewExpression (constructor, args, null);
1422 static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
1424 var parameters = method.GetParameters ();
1426 if (arguments.Count != parameters.Length)
1427 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1429 for (int i = 0; i < parameters.Length; i++) {
1430 if (arguments [i] == null)
1431 throw new ArgumentNullException ("arguments");
1433 if (!parameters [i].ParameterType.IsAssignableFrom (arguments [i].Type))
1434 throw new ArgumentException ("arguments");
1439 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1441 throw new NotImplementedException ();
1445 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1447 throw new NotImplementedException ();
1450 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1452 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1455 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1458 throw new ArgumentNullException ("type");
1460 throw new ArgumentNullException ("bounds");
1462 var array_bounds = bounds.ToReadOnlyCollection ();
1463 foreach (var expression in array_bounds)
1464 if (!IsInt (expression.Type))
1465 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1467 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1470 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1472 return NewArrayInit (type, initializers as IEnumerable<Expression>);
1475 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1478 throw new ArgumentNullException ("type");
1479 if (initializers == null)
1480 throw new ArgumentNullException ("initializers");
1482 var array_initializers = initializers.ToReadOnlyCollection ();
1484 foreach (var expression in initializers) {
1485 if (expression == null)
1486 throw new ArgumentNullException ("initializers");
1488 if (!type.IsAssignableFrom (expression.Type))
1489 throw new InvalidOperationException ();
1491 // TODO: Quote elements if type == typeof (Expression)
1494 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
1497 public static UnaryExpression Not (Expression expression)
1499 return Not (expression, null);
1502 public static UnaryExpression Not (Expression expression, MethodInfo method)
1504 method = UnaryCoreCheck ("op_LogicalNot", expression, method);
1506 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1509 public static ParameterExpression Parameter (Type type, string name)
1512 throw new ArgumentNullException ("type");
1514 return new ParameterExpression (type, name);
1517 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1519 if (propertyAccessor == null)
1520 throw new ArgumentNullException ("propertyAccessor");
1522 if (!propertyAccessor.IsStatic) {
1523 if (expression == null)
1524 throw new ArgumentNullException ("expression");
1525 if (!propertyAccessor.DeclaringType.IsAssignableFrom (expression.Type))
1526 throw new ArgumentException ("expression");
1529 var prop = GetAssociatedProperty (propertyAccessor);
1531 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
1533 return new MemberExpression (expression, prop, prop.PropertyType);
1536 static PropertyInfo GetAssociatedProperty (MethodInfo method)
1538 foreach (var prop in method.DeclaringType.GetProperties (All)) {
1539 if (prop.GetGetMethod (true) == method)
1541 if (prop.GetSetMethod (true) == method)
1548 public static MemberExpression Property (Expression expression, PropertyInfo property)
1550 if (property == null)
1551 throw new ArgumentNullException ("property");
1553 var getter = property.GetGetMethod (true);
1555 throw new ArgumentException ("getter");
1557 if (!getter.IsStatic) {
1558 if (expression == null)
1559 throw new ArgumentNullException ("expression");
1560 if (!property.DeclaringType.IsAssignableFrom (expression.Type))
1561 throw new ArgumentException ("expression");
1564 return new MemberExpression (expression, property, property.PropertyType);
1567 public static MemberExpression Property (Expression expression, string propertyName)
1569 if (expression == null)
1570 throw new ArgumentNullException ("expression");
1572 var prop = expression.Type.GetProperty (propertyName, AllInstance);
1574 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
1576 return new MemberExpression (expression, prop, prop.PropertyType);
1579 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1581 if (expression == null)
1582 throw new ArgumentNullException ("expression");
1583 if (propertyOrFieldName == null)
1584 throw new ArgumentNullException ("propertyOrFieldName");
1586 var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
1588 return new MemberExpression (expression, prop, prop.PropertyType);
1590 var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
1592 return new MemberExpression (expression, field, field.FieldType);
1594 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
1597 public static UnaryExpression Quote (Expression expression)
1599 if (expression == null)
1600 throw new ArgumentNullException ("expression");
1602 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1605 public static UnaryExpression TypeAs (Expression expression, Type type)
1607 if (expression == null)
1608 throw new ArgumentNullException ("expression");
1610 throw new ArgumentNullException ("type");
1611 if (type.IsValueType && !IsNullable (type))
1612 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1614 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1617 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1619 if (expression == null)
1620 throw new ArgumentNullException ("expression");
1622 throw new ArgumentNullException ("type");
1624 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1627 public static UnaryExpression UnaryPlus (Expression expression)
1629 return UnaryPlus (expression, null);
1632 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1634 method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
1636 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1639 internal static bool IsNullable (Type type)
1641 return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1644 internal static bool IsUnsigned (Type t)
1647 return IsUnsigned (t.GetElementType ());
1649 return t == typeof (ushort) || t == typeof (uint) || t == typeof (ulong) || t == typeof (byte);
1653 // returns the T in a a Nullable<T> type.
1655 internal static Type GetNullableOf (Type type)
1657 return type.GetGenericArguments () [0];
1661 // This method must be overwritten by derived classes to
1662 // compile the expression
1664 internal abstract void Emit (EmitContext ec);