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_LogicalAnd" || oper_name == "op_LogicalOr"){
219 if (ultype == typeof (bool)){
220 if (ultype == urtype && ltype == rtype)
223 method = GetBinaryOperator (oper_name, rtype, left, right);
228 // Use IsNumber to avoid expensive reflection.
229 if (IsNumber (ultype)){
230 if (ultype == urtype && ltype == rtype)
233 if (oper_name != null){
234 method = GetBinaryOperator (oper_name, rtype, left, right);
241 if (oper_name != null){
242 method = GetBinaryOperator (oper_name, ltype, left, right);
248 // == and != allow reference types without operators defined.
250 if (!ltype.IsValueType && !rtype.IsValueType &&
251 (oper_name == "op_Equality" || oper_name == "op_Inequality"))
254 throw new InvalidOperationException (
255 String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
260 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
261 // only ints and bools are allowed
263 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
266 throw new ArgumentNullException ("left");
268 throw new ArgumentNullException ("right");
271 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
272 if (left.Type == right.Type && (left.Type == typeof (bool) || IsInt (left.Type)))
277 method = BinaryCoreCheck (oper_name, left, right, method);
280 // The check in BinaryCoreCheck allows a bit more than we do
281 // (floats and doubles). Catch this here
283 throw new InvalidOperationException ("Types not supported");
288 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
290 Type result = method == null ? left.Type : method.ReturnType;
294 if (IsNullable (left.Type)){
295 if (!IsNullable (right.Type))
296 throw new Exception ("Assertion, internal error: left is nullable, requires right to be as well");
307 return new BinaryExpression (et, result, left, right, false, is_lifted, method, null);
310 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
312 Type result = method == null ? expression.Type : method.ReturnType;
314 return new UnaryExpression (et, expression, result, method);
317 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
320 Type ltype = left.Type;
321 Type rtype = right.Type;
322 bool lnullable = IsNullable (ltype);
323 bool rnullable = IsNullable (rtype);
327 // Implement the rules as described in "Expression.Equal" method.
330 if (lnullable == false && rnullable == false){
332 result = typeof (bool);
333 } else if (lnullable && rnullable){
335 result = liftToNull ? typeof(bool?) : typeof (bool);
337 throw new Exception ("Internal error: this should have been caught in BinaryCoreCheck");
339 ParameterInfo [] pi = method.GetParameters ();
340 Type mltype = pi [0].ParameterType;
341 Type mrtype = pi [1].ParameterType;
343 if (ltype == mltype && rtype == mrtype){
345 result = method.ReturnType;
347 else if (ltype.IsValueType && rtype.IsValueType &&
348 ((lnullable && GetNullableOf (ltype) == mltype) ||
349 (rnullable && GetNullableOf (rtype) == mrtype))){
351 if (method.ReturnType == typeof(bool)){
352 result = liftToNull ? typeof(bool?) : typeof(bool);
355 // This behavior is not documented: what
356 // happens if the result is not typeof(bool), but
357 // the parameters are nullable: the result
358 // becomes nullable<returntype>
361 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
362 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
363 //Type.GetType ("System.Nullable`1[" + method.ReturnType.ToString () + "]");
367 result = method.ReturnType;
371 return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
377 public static BinaryExpression Add (Expression left, Expression right)
379 return Add (left, right, null);
382 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
384 method = BinaryCoreCheck ("op_Addition", left, right, method);
386 return MakeSimpleBinary (ExpressionType.Add, left, right, method);
389 public static BinaryExpression AddChecked (Expression left, Expression right)
391 return AddChecked (left, right, null);
394 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
396 method = BinaryCoreCheck ("op_Addition", left, right, method);
399 // The check in BinaryCoreCheck allows a bit more than we do
400 // (byte, sbyte). Catch that here
404 Type ltype = left.Type;
406 if (ltype == typeof (byte) || ltype == typeof (sbyte))
407 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
410 return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
413 public static BinaryExpression Subtract (Expression left, Expression right)
415 return Subtract (left, right, null);
418 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
420 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
421 return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
424 public static BinaryExpression SubtractChecked (Expression left, Expression right)
426 return SubtractChecked (left, right, null);
429 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
431 method = BinaryCoreCheck ("op_Subtraction", left, right, method);
434 // The check in BinaryCoreCheck allows a bit more than we do
435 // (byte, sbyte). Catch that here
439 Type ltype = left.Type;
441 if (ltype == typeof (byte) || ltype == typeof (sbyte))
442 throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
444 return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
447 public static BinaryExpression Modulo (Expression left, Expression right)
449 return Modulo (left, right, null);
452 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
454 method = BinaryCoreCheck ("op_Modulus", left, right, method);
456 return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
459 public static BinaryExpression Multiply (Expression left, Expression right)
461 return Multiply (left, right, null);
464 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
466 method = BinaryCoreCheck ("op_Multiply", left, right, method);
468 return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
471 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
473 return MultiplyChecked (left, right, null);
476 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
478 method = BinaryCoreCheck ("op_Multiply", left, right, method);
480 return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
483 public static BinaryExpression Divide (Expression left, Expression right)
485 return Divide (left, right, null);
488 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
490 method = BinaryCoreCheck ("op_Division", left, right, method);
492 return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
495 public static BinaryExpression Power (Expression left, Expression right)
497 return Power (left, right, null);
500 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
502 method = BinaryCoreCheck (null, left, right, method);
504 if (left.Type != typeof (double))
505 throw new InvalidOperationException ("Power only supports double arguments");
507 return MakeSimpleBinary (ExpressionType.Power, left, right, method);
513 public static BinaryExpression And (Expression left, Expression right)
515 return And (left, right, null);
518 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
520 method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
522 return MakeSimpleBinary (ExpressionType.And, left, right, method);
525 public static BinaryExpression Or (Expression left, Expression right)
527 return Or (left, right, null);
530 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
532 method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
534 return MakeSimpleBinary (ExpressionType.Or, left, right, method);
537 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
539 return ExclusiveOr (left, right, null);
542 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
544 method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
546 return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
549 public static BinaryExpression LeftShift (Expression left, Expression right)
551 return LeftShift (left, right, null);
554 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
556 method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
558 return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
561 public static BinaryExpression RightShift (Expression left, Expression right)
563 return RightShift (left, right, null);
566 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
568 method = BinaryCoreCheck ("op_RightShift", left, right, method);
570 return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
576 public static BinaryExpression AndAlso (Expression left, Expression right)
578 return AndAlso (left, right, null);
581 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
583 method = BinaryCoreCheck ("op_LogicalAnd", left, right, method);
585 return MakeBoolBinary (ExpressionType.AndAlso, left, right, false, method);
588 public static BinaryExpression OrElse (Expression left, Expression right)
590 return OrElse (left, right, null);
593 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
595 method = BinaryCoreCheck ("op_LogicalOr", left, right, method);
597 return MakeBoolBinary (ExpressionType.OrElse, left, right, false, method);
603 public static BinaryExpression Equal (Expression left, Expression right)
605 return Equal (left, right, false, null);
608 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
610 method = BinaryCoreCheck ("op_Equality", left, right, method);
612 return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
615 public static BinaryExpression NotEqual (Expression left, Expression right)
617 return NotEqual (left, right, false, null);
621 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
623 method = BinaryCoreCheck ("op_Inequality", left, right, method);
625 return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
628 public static BinaryExpression GreaterThan (Expression left, Expression right)
630 return GreaterThan (left, right, false, null);
633 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
635 method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
637 return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
640 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
642 return GreaterThanOrEqual (left, right, false, null);
646 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
648 method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
650 return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
653 public static BinaryExpression LessThan (Expression left, Expression right)
655 return LessThan (left, right, false, null);
658 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
660 method = BinaryCoreCheck ("op_LessThan", left, right, method);
662 return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
665 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
667 return LessThanOrEqual (left, right, false, null);
670 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
672 method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
674 return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
681 static void ArrayCheck (Expression array)
684 throw new ArgumentNullException ("array");
685 if (!array.Type.IsArray)
686 throw new ArgumentException ("The array argument must be of type array");
689 public static BinaryExpression ArrayIndex (Expression array, Expression index)
693 throw new ArgumentNullException ("index");
694 if (array.Type.GetArrayRank () != 1)
695 throw new ArgumentException ("The array argument must be a single dimensional array");
696 if (index.Type != typeof (int))
697 throw new ArgumentException ("The index must be of type int");
699 return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
702 public static BinaryExpression Coalesce (Expression left, Expression right)
704 return Coalesce (left, right, null);
708 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
710 BinaryCoreCheck (null, left, right, null);
712 throw new NotImplementedException ();
716 // MakeBinary constructors
718 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
720 return MakeBinary (binaryType, left, right, false, null);
723 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
725 return MakeBinary (binaryType, left, right, liftToNull, method, null);
728 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
730 switch (binaryType) {
731 case ExpressionType.Add:
732 return Add (left, right, method);
733 case ExpressionType.AddChecked:
734 return AddChecked (left, right, method);
735 case ExpressionType.AndAlso:
736 return AndAlso (left, right);
737 case ExpressionType.Coalesce:
738 return Coalesce (left, right, conversion);
739 case ExpressionType.Divide:
740 return Divide (left, right, method);
741 case ExpressionType.Equal:
742 return Equal (left, right, liftToNull, method);
743 case ExpressionType.ExclusiveOr:
744 return ExclusiveOr (left, right, method);
745 case ExpressionType.GreaterThan:
746 return GreaterThan (left, right, liftToNull, method);
747 case ExpressionType.GreaterThanOrEqual:
748 return GreaterThanOrEqual (left, right, liftToNull, method);
749 case ExpressionType.LeftShift:
750 return LeftShift (left, right, method);
751 case ExpressionType.LessThan:
752 return LessThan (left, right, liftToNull, method);
753 case ExpressionType.LessThanOrEqual:
754 return LessThanOrEqual (left, right, liftToNull, method);
755 case ExpressionType.Modulo:
756 return Modulo (left, right, method);
757 case ExpressionType.Multiply:
758 return Multiply (left, right, method);
759 case ExpressionType.MultiplyChecked:
760 return MultiplyChecked (left, right, method);
761 case ExpressionType.NotEqual:
762 return NotEqual (left, right, liftToNull, method);
763 case ExpressionType.OrElse:
764 return OrElse (left, right);
765 case ExpressionType.Power:
766 return Power (left, right, method);
767 case ExpressionType.RightShift:
768 return RightShift (left, right, method);
769 case ExpressionType.Subtract:
770 return Subtract (left, right, method);
771 case ExpressionType.SubtractChecked:
772 return SubtractChecked (left, right, method);
773 case ExpressionType.And:
774 return And (left, right, method);
775 case ExpressionType.Or:
776 return Or (left, right, method);
779 throw new ArgumentException ("MakeBinary expect a binary node type");
784 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
786 return ArrayIndex (array, indexes as IEnumerable<Expression>);
789 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
794 throw new ArgumentNullException ("indexes");
796 var args = indexes.ToReadOnlyCollection ();
797 if (array.Type.GetArrayRank () != args.Count)
798 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
800 foreach (var arg in args)
801 if (arg.Type != typeof (int))
802 throw new ArgumentException ("The index must be of type int");
804 return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
807 public static UnaryExpression ArrayLength (Expression array)
810 throw new ArgumentNullException ("array");
811 if (!array.Type.IsArray)
812 throw new ArgumentException ("The type of the expression must me Array");
813 if (array.Type.GetArrayRank () != 1)
814 throw new ArgumentException ("The array must be a single dimensional array");
816 return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
820 public static MemberAssignment Bind (MemberInfo member, Expression expression)
822 throw new NotImplementedException ();
826 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
828 throw new NotImplementedException ();
831 public static MethodCallExpression Call (Expression instance, MethodInfo method)
833 return Call (instance, method, null as IEnumerable<Expression>);
836 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
838 return Call (null, method, arguments as IEnumerable<Expression>);
841 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
843 return Call (instance, method, arguments as IEnumerable<Expression>);
846 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
849 throw new ArgumentNullException ("method");
850 if (instance == null && !method.IsStatic)
851 throw new ArgumentNullException ("instance");
852 if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
853 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
855 var args = arguments.ToReadOnlyCollection ();
856 var parameters = method.GetParameters ();
858 if (args.Count != parameters.Length)
859 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
861 // TODO: check for assignability of the arguments on the parameters
863 return new MethodCallExpression (instance, method, args);
867 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
869 throw new NotImplementedException ();
873 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
875 throw new NotImplementedException ();
878 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
881 throw new ArgumentNullException ("test");
883 throw new ArgumentNullException ("ifTrue");
885 throw new ArgumentNullException ("ifFalse");
886 if (test.Type != typeof (bool))
887 throw new ArgumentException ("Test expression should be of type bool");
888 if (ifTrue.Type != ifFalse.Type)
889 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
891 return new ConditionalExpression (test, ifTrue, ifFalse);
894 public static ConstantExpression Constant (object value)
897 return new ConstantExpression (null, typeof (object));
899 return Constant (value, value.GetType ());
902 public static ConstantExpression Constant (object value, Type type)
905 throw new ArgumentNullException ("type");
908 // value must be compatible with type, no conversions
912 if (type.IsValueType && !IsNullable (type))
913 throw new ArgumentException ();
915 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
916 throw new ArgumentException ();
920 return new ConstantExpression (value, type);
924 public static UnaryExpression Convert (Expression expression, Type type)
926 throw new NotImplementedException ();
930 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
932 throw new NotImplementedException ();
936 public static UnaryExpression ConvertChecked (Expression expression, Type type)
938 throw new NotImplementedException ();
942 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
944 throw new NotImplementedException ();
948 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
950 throw new NotImplementedException ();
954 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
956 throw new NotImplementedException ();
960 public static MemberExpression Field (Expression expression, FieldInfo field)
962 throw new NotImplementedException ();
966 public static MemberExpression Field (Expression expression, string fieldName)
968 throw new NotImplementedException ();
971 public static Type GetActionType (params Type [] typeArgs)
973 if (typeArgs == null)
974 throw new ArgumentNullException ("typeArgs");
976 if (typeArgs.Length > 4)
977 throw new ArgumentException ("No Action type of this arity");
979 if (typeArgs.Length == 0)
980 return typeof (Action);
983 switch (typeArgs.Length) {
985 action = typeof (Action<>);
988 action = typeof (Action<,>);
991 action = typeof (Action<,,>);
994 action = typeof (Action<,,,>);
998 return action.MakeGenericType (typeArgs);
1001 public static Type GetFuncType (params Type [] typeArgs)
1003 if (typeArgs == null)
1004 throw new ArgumentNullException ("typeArgs");
1006 if (typeArgs.Length < 1 || typeArgs.Length > 5)
1007 throw new ArgumentException ("No Func type of this arity");
1010 switch (typeArgs.Length) {
1012 func = typeof (Func<>);
1015 func = typeof (Func<,>);
1018 func = typeof (Func<,,>);
1021 func = typeof (Func<,,,>);
1024 func = typeof (Func<,,,,>);
1028 return func.MakeGenericType (typeArgs);
1032 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1034 throw new NotImplementedException ();
1038 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1040 throw new NotImplementedException ();
1043 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1046 throw new ArgumentNullException ("body");
1048 return new Expression<TDelegate> (body, parameters);
1052 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1054 throw new NotImplementedException ();
1058 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1060 throw new NotImplementedException ();
1063 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1065 return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1069 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1071 if (delegateType == null)
1072 throw new ArgumentNullException ("delegateType");
1074 throw new ArgumentNullException ("body");
1076 return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1079 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1081 throw new NotImplementedException ();
1085 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1087 throw new NotImplementedException ();
1091 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1093 throw new NotImplementedException ();
1097 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1099 throw new NotImplementedException ();
1103 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1105 throw new NotImplementedException ();
1109 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1111 throw new NotImplementedException ();
1115 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1117 throw new NotImplementedException ();
1121 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1123 throw new NotImplementedException ();
1127 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1129 throw new NotImplementedException ();
1133 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1135 throw new NotImplementedException ();
1138 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1140 if (expression == null)
1141 throw new ArgumentNullException ("expression");
1143 throw new ArgumentNullException ("member");
1145 var field = member as FieldInfo;
1147 return Field (expression, field);
1149 var property = member as PropertyInfo;
1150 if (property != null)
1151 return Property (expression, property);
1153 throw new ArgumentException ("Member should either be a field or a property");
1156 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1158 return MakeUnary (unaryType, operand, type, null);
1161 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1163 switch (unaryType) {
1164 case ExpressionType.ArrayLength:
1165 return ArrayLength (operand);
1166 case ExpressionType.Convert:
1167 return Convert (operand, type, method);
1168 case ExpressionType.ConvertChecked:
1169 return ConvertChecked (operand, type, method);
1170 case ExpressionType.Negate:
1171 return Negate (operand, method);
1172 case ExpressionType.NegateChecked:
1173 return NegateChecked (operand, method);
1174 case ExpressionType.Not:
1175 return Not (operand, method);
1176 case ExpressionType.Quote:
1177 return Quote (operand);
1178 case ExpressionType.TypeAs:
1179 return TypeAs (operand, type);
1180 case ExpressionType.UnaryPlus:
1181 return UnaryPlus (operand, method);
1184 throw new ArgumentException ("MakeUnary expect an unary operator");
1188 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] binding)
1190 throw new NotImplementedException ();
1194 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> binding)
1196 throw new NotImplementedException ();
1200 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] binding)
1202 throw new NotImplementedException ();
1206 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> binding)
1208 throw new NotImplementedException ();
1212 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] binding)
1214 throw new NotImplementedException ();
1218 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> binding)
1220 throw new NotImplementedException ();
1223 public static UnaryExpression Negate (Expression expression)
1225 return Negate (expression, null);
1228 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1230 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1232 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1235 public static UnaryExpression NegateChecked (Expression expression)
1237 return NegateChecked (expression, null);
1240 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1242 method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1244 return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1248 public static NewExpression New (ConstructorInfo constructor)
1250 throw new NotImplementedException ();
1254 public static NewExpression New (Type type)
1256 throw new NotImplementedException ();
1260 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1262 throw new NotImplementedException ();
1266 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1268 throw new NotImplementedException ();
1272 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1274 throw new NotImplementedException ();
1278 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1280 throw new NotImplementedException ();
1284 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1286 throw new NotImplementedException ();
1290 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1292 throw new NotImplementedException ();
1296 public static NewArrayExpression NewArrayInit (Type type, params Expression [] bounds)
1298 throw new NotImplementedException ();
1302 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> bounds)
1304 throw new NotImplementedException ();
1307 public static UnaryExpression Not (Expression expression)
1309 return Not (expression, null);
1312 public static UnaryExpression Not (Expression expression, MethodInfo method)
1314 method = UnaryCoreCheck ("op_LogicalNot", expression, method);
1316 return MakeSimpleUnary (ExpressionType.Not, expression, method);
1319 public static ParameterExpression Parameter (Type type, string name)
1322 throw new ArgumentNullException ("type");
1324 return new ParameterExpression (type, name);
1328 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1330 throw new NotImplementedException ();
1334 public static MemberExpression Property (Expression expression, PropertyInfo property)
1336 throw new NotImplementedException ();
1340 public static MemberExpression Property (Expression expression, string propertyName)
1342 throw new NotImplementedException ();
1346 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1348 throw new NotImplementedException ();
1351 public static UnaryExpression Quote (Expression expression)
1353 if (expression == null)
1354 throw new ArgumentNullException ("expression");
1356 return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1359 public static UnaryExpression TypeAs (Expression expression, Type type)
1361 if (expression == null)
1362 throw new ArgumentNullException ("expression");
1364 throw new ArgumentNullException ("type");
1365 if (type.IsValueType && !IsNullable (type))
1366 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1368 return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1371 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1373 if (expression == null)
1374 throw new ArgumentNullException ("expression");
1376 throw new ArgumentNullException ("type");
1378 return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1381 public static UnaryExpression UnaryPlus (Expression expression)
1383 return UnaryPlus (expression, null);
1386 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1388 method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
1390 return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1393 static bool IsNullable (Type type)
1395 return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1398 protected static bool IsUnsigned (Type t)
1401 return IsUnsigned (t.GetElementType ());
1403 return t == typeof (ushort) || t == typeof (uint) || t == typeof (ulong) || t == typeof (byte);
1407 // returns the T in a a Nullable<T> type.
1409 static Type GetNullableOf (Type type)
1411 return type.GetGenericArguments () [0];
1415 // This method must be overwritten by derived classes to
1416 // compile the expression
1418 internal abstract void Emit (EmitContext ec);