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;
46 public ExpressionType NodeType {
47 get { return node_type; }
54 // TODO: remove when all Expression subtypes
55 // have their constructor implemented
56 protected Expression ()
60 protected Expression (ExpressionType node_type, Type type)
62 this.node_type = node_type;
66 public override string ToString ()
68 return ExpressionPrinter.ToString (this);
71 static void CheckMethod (MethodInfo m)
75 #region Binary Expressions
76 static bool IsInt (Type t)
78 return t == typeof (byte) || t == typeof (sbyte) ||
79 t == typeof (short) || t == typeof (ushort) ||
80 t == typeof (int) || t == typeof (uint) ||
81 t == typeof (long) || t == typeof (ulong);
84 static bool IsNumber (Type t)
89 return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
92 static MethodInfo GetUnaryOperator (string oper_name, Type on_type, Expression expression)
94 var methods = on_type.GetMethods (PublicStatic);
96 foreach (var method in methods) {
97 if (method.Name != oper_name)
100 var parameters = method.GetParameters ();
101 if (parameters.Length != 1)
104 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
113 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method)
115 if (expression == null)
116 throw new ArgumentNullException ("expression");
118 if (method != null) {
119 if (method.ReturnType == typeof (void))
120 throw new ArgumentException ("Specified method must return a value", "method");
122 if (!method.IsStatic)
123 throw new ArgumentException ("Method must be static", "method");
125 var parameters = method.GetParameters ();
127 if (parameters.Length != 1)
128 throw new ArgumentException ("Must have only one parameters", "method");
130 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
131 throw new InvalidOperationException ("left-side argument type does not match left expression type");
135 if (IsNumber (expression.Type))
138 if (oper_name != null) {
139 method = GetUnaryOperator (oper_name, expression.Type, expression);
144 throw new InvalidOperationException (
145 String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
149 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
151 MethodInfo [] methods = on_type.GetMethods (PublicStatic);
153 foreach (MethodInfo m in methods){
154 if (m.Name != oper_name)
157 ParameterInfo [] pi = m.GetParameters ();
161 if (!pi [0].ParameterType.IsAssignableFrom (left.Type))
164 if (!pi [1].ParameterType.IsAssignableFrom (right.Type))
167 // Method has papers in order.
175 // Performs basic checks on the incoming expressions for binary expressions
176 // and any provided MethodInfo.
178 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
181 throw new ArgumentNullException ("left");
183 throw new ArgumentNullException ("right");
186 if (method.ReturnType == typeof (void))
187 throw new ArgumentException ("Specified method must return a value", "method");
189 if (!method.IsStatic)
190 throw new ArgumentException ("Method must be static", "method");
191 ParameterInfo [] pi = method.GetParameters ();
194 throw new ArgumentException ("Must have only two parameters", "method");
196 Type ltype = left.Type.IsValueType && IsNullable (left.Type) ? GetNullableOf(left.Type) : left.Type;
197 Type rtype = left.Type.IsValueType && IsNullable (right.Type) ? GetNullableOf(right.Type) :right.Type;
199 if (ltype != pi [0].ParameterType)
200 throw new InvalidOperationException ("left-side argument type does not match left expression type");
202 if (rtype != pi [1].ParameterType)
203 throw new InvalidOperationException ("right-side argument type does not match right expression type");
207 Type ltype = left.Type;
208 Type rtype = right.Type;
209 Type ultype = left.Type;
210 Type urtype = right.Type;
212 if (IsNullable (ltype))
213 ultype = GetNullableOf (ltype);
215 if (IsNullable (rtype))
216 urtype = GetNullableOf (rtype);
218 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd"){
219 if (ultype == typeof (bool)){
220 if (ultype == urtype && ltype == rtype)
225 if (oper_name == "op_LogicalAnd" || oper_name == "op_LogicalOr"){
226 if (ultype == typeof (bool)){
227 if (ultype == urtype && ltype == rtype)
230 method = GetBinaryOperator (oper_name, rtype, left, right);
235 // Use IsNumber to avoid expensive reflection.
236 if (IsNumber (ultype)){
237 if (ultype == urtype && ltype == rtype)
240 if (oper_name != null){
241 method = GetBinaryOperator (oper_name, rtype, left, right);
248 if (oper_name != null){
249 method = GetBinaryOperator (oper_name, ltype, left, right);
255 // == and != allow reference types without operators defined.
257 if (!ltype.IsValueType && !rtype.IsValueType &&
258 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
261 throw new InvalidOperationException (
262 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
267 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
268 // only ints and bools are allowed
270 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
273 throw new ArgumentNullException ("left");
275 throw new ArgumentNullException ("right");
278 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
279 if (left.Type == right.Type && (left.Type == typeof (bool) || IsInt (left.Type)))
283 method = BinaryCoreCheck (oper_name, left, right, method);
286 // The check in BinaryCoreCheck allows a bit more than we do
287 // (floats and doubles). Catch this here
289 if (left.Type == typeof(double) || left.Type == typeof(float))
290 throw new InvalidOperationException ("Types not supported");
295 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
297 Type result = method == null ? left.Type : method.ReturnType;
301 if (IsNullable (left.Type)){
302 if (!IsNullable (right.Type))
303 throw new Exception ("Assertion, internal error: left is nullable, requires right to be as well");
314 return new BinaryExpression (et, result, left, right, false, is_lifted, method, null);
317 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
319 Type result = method == null ? expression.Type : method.ReturnType;
321 return new UnaryExpression (et, expression, result, method);
324 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
327 Type ltype = left.Type;
328 Type rtype = right.Type;
329 bool lnullable = IsNullable (ltype);
330 bool rnullable = IsNullable (rtype);
334 // Implement the rules as described in "Expression.Equal" method.
337 if (lnullable == false && rnullable == false){
339 result = typeof (bool);
340 } else if (lnullable && rnullable){
342 result = liftToNull ? typeof(bool?) : typeof (bool);
344 throw new Exception ("Internal error: this should have been caught in BinaryCoreCheck");
346 ParameterInfo [] pi = method.GetParameters ();
347 Type mltype = pi [0].ParameterType;
348 Type mrtype = pi [1].ParameterType;
350 if (ltype == mltype && rtype == mrtype){
352 result = method.ReturnType;
354 else if (ltype.IsValueType && rtype.IsValueType &&
355 ((lnullable && GetNullableOf (ltype) == mltype) ||
356 (rnullable && GetNullableOf (rtype) == mrtype))){
358 if (method.ReturnType == typeof(bool)){
359 result = liftToNull ? typeof(bool?) : typeof(bool);
362 // This behavior is not documented: what
363 // happens if the result is not typeof(bool), but
364 // the parameters are nullable: the result
365 // becomes nullable<returntype>
368 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
369 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
370 //Type.GetType ("System.Nullable`1[" + method.ReturnType.ToString () + "]");
374 result = method.ReturnType;
378 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
384 public static BinaryExpression Add (Expression left, Expression right)
386 return Add (left, right, null);
389 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
391 method = BinaryCoreCheck ("op_Addition", left, right, method);
393 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
396 public static BinaryExpression AddChecked (Expression left, Expression right)
398 return AddChecked (left, right, null);
401 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
403 method = BinaryCoreCheck ("op_Addition", left, right, method);
406 // The check in BinaryCoreCheck allows a bit more than we do
407 // (byte, sbyte). Catch that here
411 Type ltype = left.Type;
413 if (ltype == typeof (byte) || ltype == typeof (sbyte))
414 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
417 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
420 public static BinaryExpression Subtract (Expression left, Expression right)
422 return Subtract (left, right, null);
425 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
427 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
428 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
431 public static BinaryExpression SubtractChecked (Expression left, Expression right)
433 return SubtractChecked (left, right, null);
436 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
438 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
441 // The check in BinaryCoreCheck allows a bit more than we do
442 // (byte, sbyte). Catch that here
446 Type ltype = left.Type;
448 if (ltype == typeof (byte) || ltype == typeof (sbyte))
449 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
451 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
454 public static BinaryExpression Modulo (Expression left, Expression right)
456 return Modulo (left, right, null);
459 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
461 method = BinaryCoreCheck ("op_Modulus", left, right, method);
463 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
466 public static BinaryExpression Multiply (Expression left, Expression right)
468 return Multiply (left, right, null);
471 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
473 method = BinaryCoreCheck ("op_Multiply", left, right, method);
475 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
478 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
480 return MultiplyChecked (left, right, null);
483 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
485 method = BinaryCoreCheck ("op_Multiply", left, right, method);
487 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
490 public static BinaryExpression Divide (Expression left, Expression right)
492 return Divide (left, right, null);
495 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
497 method = BinaryCoreCheck ("op_Division", left, right, method);
499 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
502 public static BinaryExpression Power (Expression left, Expression right)
504 return Power (left, right, null);
507 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
509 method = BinaryCoreCheck (null, left, right, method);
511 if (left.Type != typeof (double))
512 throw new InvalidOperationException ("Power only supports double arguments");
514 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
520 public static BinaryExpression And (Expression left, Expression right)
522 return And (left, right, null);
525 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
527 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
529 return MakeSimpleBinary (ExpressionType.And, left, right, method);
532 public static BinaryExpression Or (Expression left, Expression right)
534 return Or (left, right, null);
537 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
539 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
541 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
544 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
546 return ExclusiveOr (left, right, null);
549 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
551 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
553 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
556 public static BinaryExpression LeftShift (Expression left, Expression right)
558 return LeftShift (left, right, null);
561 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
563 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
565 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
568 public static BinaryExpression RightShift (Expression left, Expression right)
570 return RightShift (left, right, null);
573 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
575 method = BinaryCoreCheck ("op_RightShift", left, right, method);
577 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
583 public static BinaryExpression AndAlso (Expression left, Expression right)
585 return AndAlso (left, right, null);
588 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
590 method = BinaryCoreCheck ("op_LogicalAnd", left, right, method);
592 return MakeBoolBinary (ExpressionType.AndAlso, left, right, false, method);
595 public static BinaryExpression OrElse (Expression left, Expression right)
597 return OrElse (left, right, null);
600 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
602 method = BinaryCoreCheck ("op_LogicalOr", left, right, method);
604 return MakeBoolBinary (ExpressionType.OrElse, left, right, false, method);
610 public static BinaryExpression Equal (Expression left, Expression right)
612 return Equal (left, right, false, null);
615 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
617 method = BinaryCoreCheck ("op_Equality", left, right, method);
619 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
622 public static BinaryExpression NotEqual (Expression left, Expression right)
624 return NotEqual (left, right, false, null);
628 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
630 method = BinaryCoreCheck ("op_Inequality", left, right, method);
632 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
635 public static BinaryExpression GreaterThan (Expression left, Expression right)
637 return GreaterThan (left, right, false, null);
640 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
642 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
644 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
647 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
649 return GreaterThanOrEqual (left, right, false, null);
653 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
655 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
657 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
660 public static BinaryExpression LessThan (Expression left, Expression right)
662 return LessThan (left, right, false, null);
665 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
667 method = BinaryCoreCheck ("op_LessThan", left, right, method);
669 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
672 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
674 return LessThanOrEqual (left, right, false, null);
677 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
679 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
681 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
688 static void ArrayCheck (Expression array)
691 throw new ArgumentNullException ("array");
692 if (!array.Type.IsArray)
693 throw new ArgumentException ("The array argument must be of type array");
696 public static BinaryExpression ArrayIndex (Expression array, Expression index)
700 throw new ArgumentNullException ("index");
701 if (array.Type.GetArrayRank () != 1)
702 throw new ArgumentException ("The array argument must be a single dimensional array");
703 if (index.Type != typeof (int))
704 throw new ArgumentException ("The index must be of type int");
706 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
709 public static BinaryExpression Coalesce (Expression left, Expression right)
711 return Coalesce (left, right, null);
714 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
717 throw new ArgumentNullException ("left");
719 throw new ArgumentNullException ("right");
722 // First arg must ne nullable (either Nullable<T> or a reference type
724 if (left.Type.IsValueType && !IsNullable (left.Type))
725 throw new InvalidOperationException ("Left expression can never be null");
729 if (IsNullable (left.Type)){
730 Type lbase = GetNullableOf (left.Type);
732 if (!IsNullable (right.Type) && lbase.IsAssignableFrom (right.Type))
736 if (result == null && left.Type.IsAssignableFrom (right.Type))
740 if (IsNullable (left.Type) && right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
746 throw new ArgumentException ("Incompatible argument types");
749 // FIXME: What do we do with "conversion"?
751 return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
755 // MakeBinary constructors
757 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
759 return MakeBinary (binaryType, left, right, false, null);
762 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
764 return MakeBinary (binaryType, left, right, liftToNull, method, null);
767 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
769 switch (binaryType) {
770 case ExpressionType.Add:
771 return Add (left, right, method);
772 case ExpressionType.AddChecked:
773 return AddChecked (left, right, method);
774 case ExpressionType.AndAlso:
775 return AndAlso (left, right);
776 case ExpressionType.Coalesce:
777 return Coalesce (left, right, conversion);
778 case ExpressionType.Divide:
779 return Divide (left, right, method);
780 case ExpressionType.Equal:
781 return Equal (left, right, liftToNull, method);
782 case ExpressionType.ExclusiveOr:
783 return ExclusiveOr (left, right, method);
784 case ExpressionType.GreaterThan:
785 return GreaterThan (left, right, liftToNull, method);
786 case ExpressionType.GreaterThanOrEqual:
787 return GreaterThanOrEqual (left, right, liftToNull, method);
788 case ExpressionType.LeftShift:
789 return LeftShift (left, right, method);
790 case ExpressionType.LessThan:
791 return LessThan (left, right, liftToNull, method);
792 case ExpressionType.LessThanOrEqual:
793 return LessThanOrEqual (left, right, liftToNull, method);
794 case ExpressionType.Modulo:
795 return Modulo (left, right, method);
796 case ExpressionType.Multiply:
797 return Multiply (left, right, method);
798 case ExpressionType.MultiplyChecked:
799 return MultiplyChecked (left, right, method);
800 case ExpressionType.NotEqual:
801 return NotEqual (left, right, liftToNull, method);
802 case ExpressionType.OrElse:
803 return OrElse (left, right);
804 case ExpressionType.Power:
805 return Power (left, right, method);
806 case ExpressionType.RightShift:
807 return RightShift (left, right, method);
808 case ExpressionType.Subtract:
809 return Subtract (left, right, method);
810 case ExpressionType.SubtractChecked:
811 return SubtractChecked (left, right, method);
812 case ExpressionType.And:
813 return And (left, right, method);
814 case ExpressionType.Or:
815 return Or (left, right, method);
818 throw new ArgumentException ("MakeBinary expect a binary node type");
823 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
825 return ArrayIndex (array, indexes as IEnumerable<Expression>);
828 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
833 throw new ArgumentNullException ("indexes");
835 var args = indexes.ToReadOnlyCollection ();
836 if (array.Type.GetArrayRank () != args.Count)
837 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
839 foreach (var arg in args)
840 if (arg.Type != typeof (int))
841 throw new ArgumentException ("The index must be of type int");
843 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
846 public static UnaryExpression ArrayLength (Expression array)
849 throw new ArgumentNullException ("array");
850 if (!array.Type.IsArray)
851 throw new ArgumentException ("The type of the expression must me Array");
852 if (array.Type.GetArrayRank () != 1)
853 throw new ArgumentException ("The array must be a single dimensional array");
855 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
859 public static MemberAssignment Bind (MemberInfo member, Expression expression)
861 throw new NotImplementedException ();
865 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
867 throw new NotImplementedException ();
870 public static MethodCallExpression Call (Expression instance, MethodInfo method)
872 return Call (instance, method, null as IEnumerable<Expression>);
875 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
877 return Call (null, method, arguments as IEnumerable<Expression>);
880 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
882 return Call (instance, method, arguments as IEnumerable<Expression>);
885 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
888 throw new ArgumentNullException ("method");
889 if (instance == null && !method.IsStatic)
890 throw new ArgumentNullException ("instance");
891 if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
892 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
894 var args = arguments.ToReadOnlyCollection ();
895 var parameters = method.GetParameters ();
897 if (args.Count != parameters.Length)
898 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
900 // TODO: check for assignability of the arguments on the parameters
902 return new MethodCallExpression (instance, method, args);
906 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
908 throw new NotImplementedException ();
912 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
914 throw new NotImplementedException ();
917 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
920 throw new ArgumentNullException ("test");
922 throw new ArgumentNullException ("ifTrue");
924 throw new ArgumentNullException ("ifFalse");
925 if (test.Type != typeof (bool))
926 throw new ArgumentException ("Test expression should be of type bool");
927 if (ifTrue.Type != ifFalse.Type)
928 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
930 return new ConditionalExpression (test, ifTrue, ifFalse);
933 public static ConstantExpression Constant (object value)
936 return new ConstantExpression (null, typeof (object));
938 return Constant (value, value.GetType ());
941 public static ConstantExpression Constant (object value, Type type)
944 throw new ArgumentNullException ("type");
947 // value must be compatible with type, no conversions
951 if (type.IsValueType && !IsNullable (type))
952 throw new ArgumentException ();
954 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
955 throw new ArgumentException ();
959 return new ConstantExpression (value, type);
963 public static UnaryExpression Convert (Expression expression, Type type)
965 throw new NotImplementedException ();
969 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
971 throw new NotImplementedException ();
975 public static UnaryExpression ConvertChecked (Expression expression, Type type)
977 throw new NotImplementedException ();
981 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
983 throw new NotImplementedException ();
987 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
989 throw new NotImplementedException ();
993 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
995 throw new NotImplementedException ();
999 public static MemberExpression Field (Expression expression, FieldInfo field)
1001 throw new NotImplementedException ();
1005 public static MemberExpression Field (Expression expression, string fieldName)
1007 throw new NotImplementedException ();
1010 public static Type GetActionType (params Type [] typeArgs)
1012 if (typeArgs == null)
1013 throw new ArgumentNullException ("typeArgs");
1015 if (typeArgs.Length > 4)
1016 throw new ArgumentException ("No Action type of this arity");
1018 if (typeArgs.Length == 0)
1019 return typeof (Action);
1022 switch (typeArgs.Length) {
1024 action = typeof (Action<>);
1027 action = typeof (Action<,>);
1030 action = typeof (Action<,,>);
1033 action = typeof (Action<,,,>);
1037 return action.MakeGenericType (typeArgs);
1040 public static Type GetFuncType (params Type [] typeArgs)
1042 if (typeArgs == null)
1043 throw new ArgumentNullException ("typeArgs");
1045 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1046 throw new ArgumentException ("No Func type of this arity");
1049 switch (typeArgs.Length) {
1051 func = typeof (Func<>);
1054 func = typeof (Func<,>);
1057 func = typeof (Func<,,>);
1060 func = typeof (Func<,,,>);
1063 func = typeof (Func<,,,,>);
1067 return func.MakeGenericType (typeArgs);
1071 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1073 throw new NotImplementedException ();
1077 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1079 throw new NotImplementedException ();
1082 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1085 throw new ArgumentNullException ("body");
1087 return new Expression<TDelegate> (body, parameters);
1091 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1093 throw new NotImplementedException ();
1097 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1099 throw new NotImplementedException ();
1102 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1104 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1108 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1110 if (delegateType == null)
1111 throw new ArgumentNullException ("delegateType");
1113 throw new ArgumentNullException ("body");
1115 return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1118 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1120 throw new NotImplementedException ();
1124 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1126 throw new NotImplementedException ();
1130 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1132 throw new NotImplementedException ();
1136 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1138 throw new NotImplementedException ();
1142 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1144 throw new NotImplementedException ();
1148 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1150 throw new NotImplementedException ();
1154 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1156 throw new NotImplementedException ();
1160 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1162 throw new NotImplementedException ();
1166 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1168 throw new NotImplementedException ();
1172 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1174 throw new NotImplementedException ();
1177 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1179 if (expression == null)
1180 throw new ArgumentNullException ("expression");
1182 throw new ArgumentNullException ("member");
1184 var field = member as FieldInfo;
1186 return Field (expression, field);
1188 var property = member as PropertyInfo;
1189 if (property != null)
1190 return Property (expression, property);
1192 throw new ArgumentException ("Member should either be a field or a property");
1195 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1197 return MakeUnary (unaryType, operand, type, null);
1200 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1202 switch (unaryType) {
1203 case ExpressionType.ArrayLength:
1204 return ArrayLength (operand);
1205 case ExpressionType.Convert:
1206 return Convert (operand, type, method);
1207 case ExpressionType.ConvertChecked:
1208 return ConvertChecked (operand, type, method);
1209 case ExpressionType.Negate:
1210 return Negate (operand, method);
1211 case ExpressionType.NegateChecked:
1212 return NegateChecked (operand, method);
1213 case ExpressionType.Not:
1214 return Not (operand, method);
1215 case ExpressionType.Quote:
1216 return Quote (operand);
1217 case ExpressionType.TypeAs:
1218 return TypeAs (operand, type);
1219 case ExpressionType.UnaryPlus:
1220 return UnaryPlus (operand, method);
1223 throw new ArgumentException ("MakeUnary expect an unary operator");
1227 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] binding)
1229 throw new NotImplementedException ();
1233 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> binding)
1235 throw new NotImplementedException ();
1239 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] binding)
1241 throw new NotImplementedException ();
1245 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> binding)
1247 throw new NotImplementedException ();
1251 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] binding)
1253 throw new NotImplementedException ();
1257 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> binding)
1259 throw new NotImplementedException ();
1262 public static UnaryExpression Negate (Expression expression)
1264 return Negate (expression, null);
1267 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1269 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1271 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1274 public static UnaryExpression NegateChecked (Expression expression)
1276 return NegateChecked (expression, null);
1279 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1281 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1283 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1287 public static NewExpression New (ConstructorInfo constructor)
1289 throw new NotImplementedException ();
1293 public static NewExpression New (Type type)
1295 throw new NotImplementedException ();
1299 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1301 throw new NotImplementedException ();
1305 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1307 throw new NotImplementedException ();
1311 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1313 throw new NotImplementedException ();
1317 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1319 throw new NotImplementedException ();
1322 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1324 return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1327 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1330 throw new ArgumentNullException ("type");
1332 throw new ArgumentNullException ("bounds");
1334 var array_bounds = bounds.ToReadOnlyCollection ();
1335 foreach (var expression in array_bounds)
1336 if (!IsInt (expression.Type))
1337 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1339 return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1342 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1344 return NewArrayInit (type, initializers as IEnumerable<Expression>);
1347 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1350 throw new ArgumentNullException ("type");
1351 if (initializers == null)
1352 throw new ArgumentNullException ("initializers");
1354 var array_initializers = initializers.ToReadOnlyCollection ();
1356 foreach (var expression in initializers) {
1357 if (expression == null)
1358 throw new ArgumentNullException ("initializers");
1360 if (!type.IsAssignableFrom (expression.Type))
1361 throw new InvalidOperationException ();
1363 // TODO: Quote elements if type == typeof (Expression)
1366 return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
1369 public static UnaryExpression Not (Expression expression)
1371 return Not (expression, null);
1374 public static UnaryExpression Not (Expression expression, MethodInfo method)
1376 method = UnaryCoreCheck ("op_LogicalNot", expression, method);
1378 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1381 public static ParameterExpression Parameter (Type type, string name)
1384 throw new ArgumentNullException ("type");
1386 return new ParameterExpression (type, name);
1390 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1392 throw new NotImplementedException ();
1396 public static MemberExpression Property (Expression expression, PropertyInfo property)
1398 throw new NotImplementedException ();
1402 public static MemberExpression Property (Expression expression, string propertyName)
1404 throw new NotImplementedException ();
1408 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1410 throw new NotImplementedException ();
1413 public static UnaryExpression Quote (Expression expression)
1415 if (expression == null)
1416 throw new ArgumentNullException ("expression");
1418 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1421 public static UnaryExpression TypeAs (Expression expression, Type type)
1423 if (expression == null)
1424 throw new ArgumentNullException ("expression");
1426 throw new ArgumentNullException ("type");
1427 if (type.IsValueType && !IsNullable (type))
1428 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1430 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1433 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1435 if (expression == null)
1436 throw new ArgumentNullException ("expression");
1438 throw new ArgumentNullException ("type");
1440 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1443 public static UnaryExpression UnaryPlus (Expression expression)
1445 return UnaryPlus (expression, null);
1448 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1450 method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
1452 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1455 internal static bool IsNullable (Type type)
1457 return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1460 internal static bool IsUnsigned (Type t)
1463 return IsUnsigned (t.GetElementType ());
1465 return t == typeof (ushort) || t == typeof (uint) || t == typeof (ulong) || t == typeof (byte);
1469 // returns the T in a a Nullable<T> type.
1471 internal static Type GetNullableOf (Type type)
1473 return type.GetGenericArguments () [0];
1477 // This method must be overwritten by derived classes to
1478 // compile the expression
1480 internal abstract void Emit (EmitContext ec);