5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
8 // (C) 2008 Novell, Inc. (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Collections
;
32 using System
.Collections
.Generic
;
33 using System
.Collections
.ObjectModel
;
34 using System
.Globalization
;
36 using System
.Reflection
;
37 using System
.Reflection
.Emit
;
39 namespace System
.Linq
.Expressions
{
41 public abstract class Expression
{
43 ExpressionType node_type
;
46 internal const BindingFlags PublicInstance
= BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.FlattenHierarchy
;
47 internal const BindingFlags NonPublicInstance
= BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.FlattenHierarchy
;
48 internal const BindingFlags PublicStatic
= BindingFlags
.Public
| BindingFlags
.Static
| BindingFlags
.FlattenHierarchy
;
49 internal const BindingFlags AllInstance
= BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.FlattenHierarchy
;
50 internal const BindingFlags AllStatic
= BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.Static
| BindingFlags
.FlattenHierarchy
;
51 internal const BindingFlags All
= BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.Static
| BindingFlags
.Instance
| BindingFlags
.FlattenHierarchy
;
53 public ExpressionType NodeType
{
54 get { return node_type; }
61 protected Expression (ExpressionType node_type
, Type type
)
63 this.node_type
= node_type
;
67 public override string ToString ()
69 return ExpressionPrinter
.ToString (this);
72 #region Binary Expressions
74 static MethodInfo
GetUnaryOperator (string oper_name
, Type declaring
, Type param
)
76 return GetUnaryOperator (oper_name
, declaring
, param
, null);
79 static MethodInfo
GetUnaryOperator (string oper_name
, Type declaring
, Type param
, Type ret
)
81 var methods
= declaring
.GetNotNullableType ().GetMethods (PublicStatic
);
83 foreach (var method
in methods
) {
84 if (method
.Name
!= oper_name
)
87 var parameters
= method
.GetParameters ();
88 if (parameters
.Length
!= 1)
91 if (method
.IsGenericMethod
)
94 if (!IsAssignableToParameterType (param
.GetNotNullableType (), parameters
[0]))
97 if (ret
!= null && method
.ReturnType
!= ret
.GetNotNullableType ())
106 internal static MethodInfo
GetTrueOperator (Type self
)
108 return GetBooleanOperator ("op_True", self
);
111 internal static MethodInfo
GetFalseOperator (Type self
)
113 return GetBooleanOperator ("op_False", self
);
116 static MethodInfo
GetBooleanOperator (string op
, Type self
)
118 return GetUnaryOperator (op
, self
, self
, typeof (bool));
121 static bool IsAssignableToParameterType (Type type
, ParameterInfo param
)
123 var ptype
= param
.ParameterType
;
125 ptype
= ptype
.GetElementType ();
127 return type
.GetNotNullableType ().IsAssignableTo (ptype
);
130 static MethodInfo
CheckUnaryMethod (MethodInfo method
, Type param
)
132 if (method
.ReturnType
== typeof (void))
133 throw new ArgumentException ("Specified method must return a value", "method");
135 if (!method
.IsStatic
)
136 throw new ArgumentException ("Method must be static", "method");
138 var parameters
= method
.GetParameters ();
140 if (parameters
.Length
!= 1)
141 throw new ArgumentException ("Must have only one parameters", "method");
143 if (!IsAssignableToParameterType (param
.GetNotNullableType (), parameters
[0]))
144 throw new InvalidOperationException ("left-side argument type does not match expression type");
149 static MethodInfo
UnaryCoreCheck (string oper_name
, Expression expression
, MethodInfo method
, Func
<Type
, bool> validator
)
151 if (expression
== null)
152 throw new ArgumentNullException ("expression");
155 return CheckUnaryMethod (method
, expression
.Type
);
157 var type
= expression
.Type
.GetNotNullableType ();
159 if (validator (type
))
162 if (oper_name
!= null) {
163 method
= GetUnaryOperator (oper_name
, type
, expression
.Type
);
168 throw new InvalidOperationException (
169 string.Format ("Operation {0} not defined for {1}", oper_name
!= null ? oper_name
.Substring (3) : "is", expression
.Type
));
172 static MethodInfo
GetBinaryOperator (string oper_name
, Type on_type
, Expression left
, Expression right
)
174 MethodInfo
[] methods
= on_type
.GetMethods (PublicStatic
);
176 foreach (var method
in methods
) {
177 if (method
.Name
!= oper_name
)
180 var parameters
= method
.GetParameters ();
181 if (parameters
.Length
!= 2)
184 if (method
.IsGenericMethod
)
187 if (!IsAssignableToParameterType (left
.Type
, parameters
[0]))
190 if (!IsAssignableToParameterType (right
.Type
, parameters
[1]))
193 // Method has papers in order.
201 // Performs basic checks on the incoming expressions for binary expressions
202 // and any provided MethodInfo.
204 static MethodInfo
BinaryCoreCheck (string oper_name
, Expression left
, Expression right
, MethodInfo method
)
207 throw new ArgumentNullException ("left");
209 throw new ArgumentNullException ("right");
212 if (method
.ReturnType
== typeof (void))
213 throw new ArgumentException ("Specified method must return a value", "method");
215 if (!method
.IsStatic
)
216 throw new ArgumentException ("Method must be static", "method");
218 var parameters
= method
.GetParameters ();
220 if (parameters
.Length
!= 2)
221 throw new ArgumentException ("Must have only two parameters", "method");
223 if (!IsAssignableToParameterType (left
.Type
, parameters
[0]))
224 throw new InvalidOperationException ("left-side argument type does not match left expression type");
226 if (!IsAssignableToParameterType (right
.Type
, parameters
[1]))
227 throw new InvalidOperationException ("right-side argument type does not match right expression type");
231 Type ltype
= left
.Type
;
232 Type rtype
= right
.Type
;
233 Type ultype
= ltype
.GetNotNullableType ();
234 Type urtype
= rtype
.GetNotNullableType ();
236 if (oper_name
== "op_BitwiseOr" || oper_name
== "op_BitwiseAnd") {
237 if (ultype
== typeof (bool)) {
238 if (ultype
== urtype
&& ltype
== rtype
)
243 // Use IsNumber to avoid expensive reflection.
244 if (IsNumber (ultype
)) {
245 if (ultype
== urtype
&& ltype
== rtype
)
248 if (oper_name
!= null){
249 method
= GetBinaryOperator (oper_name
, urtype
, left
, right
);
255 if (oper_name
!= null){
256 method
= GetBinaryOperator (oper_name
, ultype
, left
, right
);
261 if (oper_name
== "op_Equality" || oper_name
== "op_Inequality") {
263 // == and != allow reference types without operators defined.
265 if (!ltype
.IsValueType
&& !rtype
.IsValueType
)
268 if (ltype
== rtype
&& ultype
.IsEnum
)
271 if (ltype
== rtype
&& ultype
== typeof (bool))
275 if (oper_name
== "op_LeftShift" || oper_name
== "op_RightShift") {
276 if (IsInt (ultype
) && urtype
== typeof (int))
280 throw new InvalidOperationException (
281 String
.Format ("Operation {0} not defined for {1} and {2}", oper_name
!= null ? oper_name
.Substring (3) : "is", ltype
, rtype
));
286 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
287 // only ints and bools are allowed
289 static MethodInfo
BinaryBitwiseCoreCheck (string oper_name
, Expression left
, Expression right
, MethodInfo method
)
292 throw new ArgumentNullException ("left");
294 throw new ArgumentNullException ("right");
296 if (method
== null) {
297 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
298 if (left
.Type
== right
.Type
&& IsIntOrBool (left
.Type
))
302 method
= BinaryCoreCheck (oper_name
, left
, right
, method
);
303 if (method
== null) {
304 // The check in BinaryCoreCheck allows a bit more than we do
305 // (floats and doubles). Catch this here
306 if (left
.Type
== typeof (double) || left
.Type
== typeof (float))
307 throw new InvalidOperationException ("Types not supported");
313 static BinaryExpression
MakeSimpleBinary (ExpressionType et
, Expression left
, Expression right
, MethodInfo method
)
318 if (method
== null) {
319 is_lifted
= left
.Type
.IsNullable ();
322 var parameters
= method
.GetParameters ();
324 var lp
= parameters
[0];
325 var rp
= parameters
[1];
327 if (IsAssignableToOperatorParameter (left
, lp
) && IsAssignableToOperatorParameter (right
, rp
)) {
329 type
= method
.ReturnType
;
330 } else if (left
.Type
.IsNullable ()
331 && right
.Type
.IsNullable ()
332 && left
.Type
.GetNotNullableType () == lp
.ParameterType
333 && right
.Type
.GetNotNullableType () == rp
.ParameterType
334 && !method
.ReturnType
.IsNullable ()) {
337 type
= method
.ReturnType
.MakeNullableType ();
339 throw new InvalidOperationException ();
342 return new BinaryExpression (et
, type
, left
, right
, is_lifted
, is_lifted
, method
, null);
345 static bool IsAssignableToOperatorParameter (Expression expression
, ParameterInfo parameter
)
347 if (expression
.Type
== parameter
.ParameterType
)
350 if ((!expression
.Type
.IsNullable () && !parameter
.ParameterType
.IsNullable ())
351 && IsAssignableToParameterType (expression
.Type
, parameter
))
357 static UnaryExpression
MakeSimpleUnary (ExpressionType et
, Expression expression
, MethodInfo method
)
362 if (method
== null) {
363 type
= expression
.Type
;
364 is_lifted
= type
.IsNullable ();
366 var parameter
= method
.GetParameters () [0];
368 if (IsAssignableToOperatorParameter (expression
, parameter
)) {
370 type
= method
.ReturnType
;
371 } else if (expression
.Type
.IsNullable ()
372 && expression
.Type
.GetNotNullableType () == parameter
.ParameterType
373 && !method
.ReturnType
.IsNullable ()) {
376 type
= method
.ReturnType
.MakeNullableType ();
378 throw new InvalidOperationException ();
381 return new UnaryExpression (et
, expression
, type
, method
, is_lifted
);
384 static BinaryExpression
MakeBoolBinary (ExpressionType et
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
389 if (method
== null) {
390 if (!left
.Type
.IsNullable () && !right
.Type
.IsNullable ()) {
393 type
= typeof (bool);
394 } else if (left
.Type
.IsNullable () && right
.Type
.IsNullable ()) {
396 type
= liftToNull
? typeof (bool?) : typeof (bool);
398 throw new InvalidOperationException ();
400 var parameters
= method
.GetParameters ();
402 var lp
= parameters
[0];
403 var rp
= parameters
[1];
405 if (IsAssignableToOperatorParameter (left
, lp
) && IsAssignableToOperatorParameter (right
, rp
)) {
408 type
= method
.ReturnType
;
409 } else if (left
.Type
.IsNullable ()
410 && right
.Type
.IsNullable ()
411 && left
.Type
.GetNotNullableType () == lp
.ParameterType
412 && right
.Type
.GetNotNullableType () == rp
.ParameterType
) {
416 if (method
.ReturnType
== typeof (bool))
417 type
= liftToNull
? typeof (bool?) : typeof (bool);
418 else if (!method
.ReturnType
.IsNullable ()) {
420 // This behavior is not documented: what
421 // happens if the result is not typeof(bool), but
422 // the parameters are nullable: the result
423 // becomes nullable<returntype>
426 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
428 type
= method
.ReturnType
.MakeNullableType ();
430 throw new InvalidOperationException ();
432 throw new InvalidOperationException ();
435 return new BinaryExpression (et
, type
, left
, right
, liftToNull
, is_lifted
, method
, null);
441 public static BinaryExpression
Add (Expression left
, Expression right
)
443 return Add (left
, right
, null);
446 public static BinaryExpression
Add (Expression left
, Expression right
, MethodInfo method
)
448 method
= BinaryCoreCheck ("op_Addition", left
, right
, method
);
450 return MakeSimpleBinary (ExpressionType
.Add
, left
, right
, method
);
453 public static BinaryExpression
AddChecked (Expression left
, Expression right
)
455 return AddChecked (left
, right
, null);
458 public static BinaryExpression
AddChecked (Expression left
, Expression right
, MethodInfo method
)
460 method
= BinaryCoreCheck ("op_Addition", left
, right
, method
);
462 // The check in BinaryCoreCheck allows a bit more than we do
463 // (byte, sbyte). Catch that here
464 if (method
== null) {
465 if (left
.Type
== typeof (byte) || left
.Type
== typeof (sbyte))
466 throw new InvalidOperationException (String
.Format ("AddChecked not defined for {0} and {1}", left
.Type
, right
.Type
));
469 return MakeSimpleBinary (ExpressionType
.AddChecked
, left
, right
, method
);
472 public static BinaryExpression
Subtract (Expression left
, Expression right
)
474 return Subtract (left
, right
, null);
477 public static BinaryExpression
Subtract (Expression left
, Expression right
, MethodInfo method
)
479 method
= BinaryCoreCheck ("op_Subtraction", left
, right
, method
);
481 return MakeSimpleBinary (ExpressionType
.Subtract
, left
, right
, method
);
484 public static BinaryExpression
SubtractChecked (Expression left
, Expression right
)
486 return SubtractChecked (left
, right
, null);
489 public static BinaryExpression
SubtractChecked (Expression left
, Expression right
, MethodInfo method
)
491 method
= BinaryCoreCheck ("op_Subtraction", left
, right
, method
);
493 // The check in BinaryCoreCheck allows a bit more than we do
494 // (byte, sbyte). Catch that here
495 if (method
== null) {
496 if (left
.Type
== typeof (byte) || left
.Type
== typeof (sbyte))
497 throw new InvalidOperationException (String
.Format ("SubtractChecked not defined for {0} and {1}", left
.Type
, right
.Type
));
500 return MakeSimpleBinary (ExpressionType
.SubtractChecked
, left
, right
, method
);
503 public static BinaryExpression
Modulo (Expression left
, Expression right
)
505 return Modulo (left
, right
, null);
508 public static BinaryExpression
Modulo (Expression left
, Expression right
, MethodInfo method
)
510 method
= BinaryCoreCheck ("op_Modulus", left
, right
, method
);
512 return MakeSimpleBinary (ExpressionType
.Modulo
, left
, right
, method
);
515 public static BinaryExpression
Multiply (Expression left
, Expression right
)
517 return Multiply (left
, right
, null);
520 public static BinaryExpression
Multiply (Expression left
, Expression right
, MethodInfo method
)
522 method
= BinaryCoreCheck ("op_Multiply", left
, right
, method
);
524 return MakeSimpleBinary (ExpressionType
.Multiply
, left
, right
, method
);
527 public static BinaryExpression
MultiplyChecked (Expression left
, Expression right
)
529 return MultiplyChecked (left
, right
, null);
532 public static BinaryExpression
MultiplyChecked (Expression left
, Expression right
, MethodInfo method
)
534 method
= BinaryCoreCheck ("op_Multiply", left
, right
, method
);
536 return MakeSimpleBinary (ExpressionType
.MultiplyChecked
, left
, right
, method
);
539 public static BinaryExpression
Divide (Expression left
, Expression right
)
541 return Divide (left
, right
, null);
544 public static BinaryExpression
Divide (Expression left
, Expression right
, MethodInfo method
)
546 method
= BinaryCoreCheck ("op_Division", left
, right
, method
);
548 return MakeSimpleBinary (ExpressionType
.Divide
, left
, right
, method
);
551 public static BinaryExpression
Power (Expression left
, Expression right
)
553 return Power (left
, right
, null);
556 public static BinaryExpression
Power (Expression left
, Expression right
, MethodInfo method
)
558 method
= BinaryCoreCheck (null, left
, right
, method
);
560 if (left
.Type
.GetNotNullableType () != typeof (double))
561 throw new InvalidOperationException ("Power only supports double arguments");
563 return MakeSimpleBinary (ExpressionType
.Power
, left
, right
, method
);
569 public static BinaryExpression
And (Expression left
, Expression right
)
571 return And (left
, right
, null);
574 public static BinaryExpression
And (Expression left
, Expression right
, MethodInfo method
)
576 method
= BinaryBitwiseCoreCheck ("op_BitwiseAnd", left
, right
, method
);
578 return MakeSimpleBinary (ExpressionType
.And
, left
, right
, method
);
581 public static BinaryExpression
Or (Expression left
, Expression right
)
583 return Or (left
, right
, null);
586 public static BinaryExpression
Or (Expression left
, Expression right
, MethodInfo method
)
588 method
= BinaryBitwiseCoreCheck ("op_BitwiseOr", left
, right
, method
);
590 return MakeSimpleBinary (ExpressionType
.Or
, left
, right
, method
);
593 public static BinaryExpression
ExclusiveOr (Expression left
, Expression right
)
595 return ExclusiveOr (left
, right
, null);
598 public static BinaryExpression
ExclusiveOr (Expression left
, Expression right
, MethodInfo method
)
600 method
= BinaryBitwiseCoreCheck ("op_ExclusiveOr", left
, right
, method
);
602 return MakeSimpleBinary (ExpressionType
.ExclusiveOr
, left
, right
, method
);
605 public static BinaryExpression
LeftShift (Expression left
, Expression right
)
607 return LeftShift (left
, right
, null);
610 public static BinaryExpression
LeftShift (Expression left
, Expression right
, MethodInfo method
)
612 method
= BinaryBitwiseCoreCheck ("op_LeftShift", left
, right
, method
);
614 return MakeSimpleBinary (ExpressionType
.LeftShift
, left
, right
, method
);
617 public static BinaryExpression
RightShift (Expression left
, Expression right
)
619 return RightShift (left
, right
, null);
622 public static BinaryExpression
RightShift (Expression left
, Expression right
, MethodInfo method
)
624 method
= BinaryCoreCheck ("op_RightShift", left
, right
, method
);
626 return MakeSimpleBinary (ExpressionType
.RightShift
, left
, right
, method
);
632 public static BinaryExpression
AndAlso (Expression left
, Expression right
)
634 return AndAlso (left
, right
, null);
637 public static BinaryExpression
AndAlso (Expression left
, Expression right
, MethodInfo method
)
639 method
= ConditionalBinaryCheck ("op_BitwiseAnd", left
, right
, method
);
641 return MakeBoolBinary (ExpressionType
.AndAlso
, left
, right
, true, method
);
644 static MethodInfo
ConditionalBinaryCheck (string oper
, Expression left
, Expression right
, MethodInfo method
)
646 method
= BinaryCoreCheck (oper
, left
, right
, method
);
648 if (method
== null) {
649 if (left
.Type
.GetNotNullableType () != typeof (bool))
650 throw new InvalidOperationException ("Only booleans are allowed");
652 var type
= left
.Type
.GetNotNullableType ();
654 // The method should have identical parameter and return types.
655 if (left
.Type
!= right
.Type
|| method
.ReturnType
!= type
)
656 throw new ArgumentException ("left, right and return type must match");
658 var optrue
= GetTrueOperator (type
);
659 var opfalse
= GetFalseOperator (type
);
661 if (optrue
== null || opfalse
== null)
662 throw new ArgumentException ("Operators true and false are required but not defined");
668 public static BinaryExpression
OrElse (Expression left
, Expression right
)
670 return OrElse (left
, right
, null);
673 public static BinaryExpression
OrElse (Expression left
, Expression right
, MethodInfo method
)
675 method
= ConditionalBinaryCheck ("op_BitwiseOr", left
, right
, method
);
677 return MakeBoolBinary (ExpressionType
.OrElse
, left
, right
, true, method
);
683 public static BinaryExpression
Equal (Expression left
, Expression right
)
685 return Equal (left
, right
, false, null);
688 public static BinaryExpression
Equal (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
690 method
= BinaryCoreCheck ("op_Equality", left
, right
, method
);
692 return MakeBoolBinary (ExpressionType
.Equal
, left
, right
, liftToNull
, method
);
695 public static BinaryExpression
NotEqual (Expression left
, Expression right
)
697 return NotEqual (left
, right
, false, null);
701 public static BinaryExpression
NotEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
703 method
= BinaryCoreCheck ("op_Inequality", left
, right
, method
);
705 return MakeBoolBinary (ExpressionType
.NotEqual
, left
, right
, liftToNull
, method
);
708 public static BinaryExpression
GreaterThan (Expression left
, Expression right
)
710 return GreaterThan (left
, right
, false, null);
713 public static BinaryExpression
GreaterThan (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
715 method
= BinaryCoreCheck ("op_GreaterThan", left
, right
, method
);
717 return MakeBoolBinary (ExpressionType
.GreaterThan
, left
, right
, liftToNull
, method
);
720 public static BinaryExpression
GreaterThanOrEqual (Expression left
, Expression right
)
722 return GreaterThanOrEqual (left
, right
, false, null);
726 public static BinaryExpression
GreaterThanOrEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
728 method
= BinaryCoreCheck ("op_GreaterThanOrEqual", left
, right
, method
);
730 return MakeBoolBinary (ExpressionType
.GreaterThanOrEqual
, left
, right
, liftToNull
, method
);
733 public static BinaryExpression
LessThan (Expression left
, Expression right
)
735 return LessThan (left
, right
, false, null);
738 public static BinaryExpression
LessThan (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
740 method
= BinaryCoreCheck ("op_LessThan", left
, right
, method
);
742 return MakeBoolBinary (ExpressionType
.LessThan
, left
, right
, liftToNull
, method
);
745 public static BinaryExpression
LessThanOrEqual (Expression left
, Expression right
)
747 return LessThanOrEqual (left
, right
, false, null);
750 public static BinaryExpression
LessThanOrEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
752 method
= BinaryCoreCheck ("op_LessThanOrEqual", left
, right
, method
);
754 return MakeBoolBinary (ExpressionType
.LessThanOrEqual
, left
, right
, liftToNull
, method
);
761 static void CheckArray (Expression array
)
764 throw new ArgumentNullException ("array");
765 if (!array
.Type
.IsArray
)
766 throw new ArgumentException ("The array argument must be of type array");
769 public static BinaryExpression
ArrayIndex (Expression array
, Expression index
)
774 throw new ArgumentNullException ("index");
775 if (array
.Type
.GetArrayRank () != 1)
776 throw new ArgumentException ("The array argument must be a single dimensional array");
777 if (index
.Type
!= typeof (int))
778 throw new ArgumentException ("The index must be of type int");
780 return new BinaryExpression (ExpressionType
.ArrayIndex
, array
.Type
.GetElementType (), array
, index
);
783 public static BinaryExpression
Coalesce (Expression left
, Expression right
)
785 return Coalesce (left
, right
, null);
788 static BinaryExpression
MakeCoalesce (Expression left
, Expression right
)
792 if (left
.Type
.IsNullable ()) {
793 Type lbase
= left
.Type
.GetNotNullableType ();
795 if (!right
.Type
.IsNullable () && right
.Type
.IsAssignableTo (lbase
))
799 if (result
== null && right
.Type
.IsAssignableTo (left
.Type
))
802 if (result
== null) {
803 if (left
.Type
.IsNullable () && left
.Type
.GetNotNullableType ().IsAssignableTo (right
.Type
))
808 throw new ArgumentException ("Incompatible argument types");
810 return new BinaryExpression (ExpressionType
.Coalesce
, result
, left
, right
, false, false, null, null);
813 static BinaryExpression
MakeConvertedCoalesce (Expression left
, Expression right
, LambdaExpression conversion
)
815 var invoke
= conversion
.Type
.GetInvokeMethod ();
817 CheckNotVoid (invoke
.ReturnType
);
819 if (invoke
.ReturnType
!= right
.Type
)
820 throw new InvalidOperationException ("Conversion return type doesn't march right type");
822 var parameters
= invoke
.GetParameters ();
824 if (parameters
.Length
!= 1)
825 throw new ArgumentException ("Conversion has wrong number of parameters");
827 if (!IsAssignableToParameterType (left
.Type
, parameters
[0]))
828 throw new InvalidOperationException ("Conversion argument doesn't marcht left type");
830 return new BinaryExpression (ExpressionType
.Coalesce
, right
.Type
, left
, right
, false, false, null, conversion
);
833 public static BinaryExpression
Coalesce (Expression left
, Expression right
, LambdaExpression conversion
)
836 throw new ArgumentNullException ("left");
838 throw new ArgumentNullException ("right");
841 // First arg must ne nullable (either Nullable<T> or a reference type
843 if (left
.Type
.IsValueType
&& !left
.Type
.IsNullable ())
844 throw new InvalidOperationException ("Left expression can never be null");
846 if (conversion
!= null)
847 return MakeConvertedCoalesce (left
, right
, conversion
);
849 return MakeCoalesce (left
, right
);
853 // MakeBinary constructors
855 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
)
857 return MakeBinary (binaryType
, left
, right
, false, null);
860 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
862 return MakeBinary (binaryType
, left
, right
, liftToNull
, method
, null);
865 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
, LambdaExpression conversion
)
867 switch (binaryType
) {
868 case ExpressionType
.Add
:
869 return Add (left
, right
, method
);
870 case ExpressionType
.AddChecked
:
871 return AddChecked (left
, right
, method
);
872 case ExpressionType
.AndAlso
:
873 return AndAlso (left
, right
);
874 case ExpressionType
.Coalesce
:
875 return Coalesce (left
, right
, conversion
);
876 case ExpressionType
.Divide
:
877 return Divide (left
, right
, method
);
878 case ExpressionType
.Equal
:
879 return Equal (left
, right
, liftToNull
, method
);
880 case ExpressionType
.ExclusiveOr
:
881 return ExclusiveOr (left
, right
, method
);
882 case ExpressionType
.GreaterThan
:
883 return GreaterThan (left
, right
, liftToNull
, method
);
884 case ExpressionType
.GreaterThanOrEqual
:
885 return GreaterThanOrEqual (left
, right
, liftToNull
, method
);
886 case ExpressionType
.LeftShift
:
887 return LeftShift (left
, right
, method
);
888 case ExpressionType
.LessThan
:
889 return LessThan (left
, right
, liftToNull
, method
);
890 case ExpressionType
.LessThanOrEqual
:
891 return LessThanOrEqual (left
, right
, liftToNull
, method
);
892 case ExpressionType
.Modulo
:
893 return Modulo (left
, right
, method
);
894 case ExpressionType
.Multiply
:
895 return Multiply (left
, right
, method
);
896 case ExpressionType
.MultiplyChecked
:
897 return MultiplyChecked (left
, right
, method
);
898 case ExpressionType
.NotEqual
:
899 return NotEqual (left
, right
, liftToNull
, method
);
900 case ExpressionType
.OrElse
:
901 return OrElse (left
, right
);
902 case ExpressionType
.Power
:
903 return Power (left
, right
, method
);
904 case ExpressionType
.RightShift
:
905 return RightShift (left
, right
, method
);
906 case ExpressionType
.Subtract
:
907 return Subtract (left
, right
, method
);
908 case ExpressionType
.SubtractChecked
:
909 return SubtractChecked (left
, right
, method
);
910 case ExpressionType
.And
:
911 return And (left
, right
, method
);
912 case ExpressionType
.Or
:
913 return Or (left
, right
, method
);
916 throw new ArgumentException ("MakeBinary expect a binary node type");
921 public static MethodCallExpression
ArrayIndex (Expression array
, params Expression
[] indexes
)
923 return ArrayIndex (array
, indexes
as IEnumerable
<Expression
>);
926 public static MethodCallExpression
ArrayIndex (Expression array
, IEnumerable
<Expression
> indexes
)
931 throw new ArgumentNullException ("indexes");
933 var args
= indexes
.ToReadOnlyCollection ();
934 if (array
.Type
.GetArrayRank () != args
.Count
)
935 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
937 foreach (var arg
in args
)
938 if (arg
.Type
!= typeof (int))
939 throw new ArgumentException ("The index must be of type int");
941 return Call (array
, array
.Type
.GetMethod ("Get", PublicInstance
), args
);
944 public static UnaryExpression
ArrayLength (Expression array
)
947 throw new ArgumentNullException ("array");
948 if (!array
.Type
.IsArray
)
949 throw new ArgumentException ("The type of the expression must me Array");
950 if (array
.Type
.GetArrayRank () != 1)
951 throw new ArgumentException ("The array must be a single dimensional array");
953 return new UnaryExpression (ExpressionType
.ArrayLength
, array
, typeof (int));
956 public static MemberAssignment
Bind (MemberInfo member
, Expression expression
)
959 throw new ArgumentNullException ("member");
960 if (expression
== null)
961 throw new ArgumentNullException ("expression");
965 var prop
= member
as PropertyInfo
;
966 if (prop
!= null && prop
.GetSetMethod (true) != null)
967 type
= prop
.PropertyType
;
969 var field
= member
as FieldInfo
;
971 type
= field
.FieldType
;
974 throw new ArgumentException ("member");
976 if (!expression
.Type
.IsAssignableTo (type
))
977 throw new ArgumentException ("member");
979 return new MemberAssignment (member
, expression
);
982 public static MemberAssignment
Bind (MethodInfo propertyAccessor
, Expression expression
)
984 if (propertyAccessor
== null)
985 throw new ArgumentNullException ("propertyAccessor");
986 if (expression
== null)
987 throw new ArgumentNullException ("expression");
989 CheckNonGenericMethod (propertyAccessor
);
991 var prop
= GetAssociatedProperty (propertyAccessor
);
993 throw new ArgumentException ("propertyAccessor");
995 var setter
= prop
.GetSetMethod (true);
997 throw new ArgumentException ("setter");
999 if (!expression
.Type
.IsAssignableTo (prop
.PropertyType
))
1000 throw new ArgumentException ("member");
1002 return new MemberAssignment (prop
, expression
);
1005 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
)
1007 return Call (instance
, method
, null as IEnumerable
<Expression
>);
1010 public static MethodCallExpression
Call (MethodInfo method
, params Expression
[] arguments
)
1012 return Call (null, method
, arguments
as IEnumerable
<Expression
>);
1015 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
, params Expression
[] arguments
)
1017 return Call (instance
, method
, arguments
as IEnumerable
<Expression
>);
1020 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
, IEnumerable
<Expression
> arguments
)
1023 throw new ArgumentNullException ("method");
1024 if (instance
== null && !method
.IsStatic
)
1025 throw new ArgumentNullException ("instance");
1026 if (method
.IsStatic
&& instance
!= null)
1027 throw new ArgumentException ("instance");
1028 if (!method
.IsStatic
&& !instance
.Type
.IsAssignableTo (method
.DeclaringType
))
1029 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
1031 var args
= CheckMethodArguments (method
, arguments
);
1033 return new MethodCallExpression (instance
, method
, args
);
1036 static Type
[] CollectTypes (IEnumerable
<Expression
> expressions
)
1038 return (from arg
in expressions
select arg
.Type
).ToArray ();
1041 static MethodInfo
TryMakeGeneric (MethodInfo method
, Type
[] args
)
1046 if (!method
.IsGenericMethod
&& args
== null)
1049 if (args
.Length
== method
.GetGenericArguments ().Length
)
1050 return method
.MakeGenericMethod (args
);
1055 public static MethodCallExpression
Call (Expression instance
, string methodName
, Type
[] typeArguments
, params Expression
[] arguments
)
1057 if (instance
== null)
1058 throw new ArgumentNullException ("instance");
1059 if (methodName
== null)
1060 throw new ArgumentNullException ("methodName");
1062 var method
= TryGetMethod (instance
.Type
, methodName
, AllInstance
,
1063 CollectTypes (arguments
), typeArguments
);
1065 var args
= CheckMethodArguments (method
, arguments
);
1067 return new MethodCallExpression (instance
, method
, args
);
1070 static bool MethodMatch (MethodInfo method
, string name
, Type
[] parameterTypes
, Type
[] argumentTypes
)
1072 if (method
.Name
!= name
)
1075 var parameters
= method
.GetParameters ();
1077 if (parameters
.Length
!= parameterTypes
.Length
)
1080 if (method
.IsGenericMethod
&& method
.IsGenericMethodDefinition
) {
1081 var closed
= TryMakeGeneric (method
, argumentTypes
);
1085 return MethodMatch (closed
, name
, parameterTypes
, argumentTypes
);
1086 } else if (!method
.IsGenericMethod
&& (argumentTypes
!= null && argumentTypes
.Length
> 0))
1089 for (int i
= 0; i
< parameters
.Length
; i
++) {
1090 var type
= parameterTypes
[i
];
1091 var parameter
= parameters
[i
];
1092 if (!IsAssignableToParameterType (type
, parameter
)
1093 && !IsExpressionOfParameter (type
, parameter
.ParameterType
))
1100 static bool IsExpressionOfParameter (Type type
, Type ptype
)
1102 return ptype
.IsGenericInstanceOf (typeof (Expression
<>)) && ptype
.GetFirstGenericArgument () == type
;
1105 static MethodInfo
TryGetMethod (Type type
, string methodName
, BindingFlags flags
, Type
[] parameterTypes
, Type
[] argumentTypes
)
1107 var methods
= from meth
in type
.GetMethods (flags
)
1108 where
MethodMatch (meth
, methodName
, parameterTypes
, argumentTypes
)
1111 if (methods
.Count () > 1)
1112 throw new InvalidOperationException ("Too many method candidates");
1114 var method
= TryMakeGeneric (methods
.FirstOrDefault (), argumentTypes
);
1118 throw new InvalidOperationException ("No such method");
1121 public static MethodCallExpression
Call (Type type
, string methodName
, Type
[] typeArguments
, params Expression
[] arguments
)
1124 throw new ArgumentNullException ("type");
1125 if (methodName
== null)
1126 throw new ArgumentNullException ("methodName");
1128 var method
= TryGetMethod (type
, methodName
, AllStatic
,
1129 CollectTypes (arguments
), typeArguments
);
1131 var args
= CheckMethodArguments (method
, arguments
);
1133 return new MethodCallExpression (method
, args
);
1136 public static ConditionalExpression
Condition (Expression test
, Expression ifTrue
, Expression ifFalse
)
1139 throw new ArgumentNullException ("test");
1141 throw new ArgumentNullException ("ifTrue");
1142 if (ifFalse
== null)
1143 throw new ArgumentNullException ("ifFalse");
1144 if (test
.Type
!= typeof (bool))
1145 throw new ArgumentException ("Test expression should be of type bool");
1146 if (ifTrue
.Type
!= ifFalse
.Type
)
1147 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1149 return new ConditionalExpression (test
, ifTrue
, ifFalse
);
1152 public static ConstantExpression
Constant (object value)
1155 return new ConstantExpression (null, typeof (object));
1157 return Constant (value, value.GetType ());
1160 public static ConstantExpression
Constant (object value, Type type
)
1163 throw new ArgumentNullException ("type");
1166 // value must be compatible with type, no conversions
1170 if (type
.IsValueType
&& !type
.IsNullable ())
1171 throw new ArgumentException ();
1173 if (!(type
.IsValueType
&& type
.IsNullable ()) && !value.GetType ().IsAssignableTo (type
))
1174 throw new ArgumentException ();
1178 return new ConstantExpression (value, type
);
1181 static bool IsConvertiblePrimitive (Type type
)
1183 var t
= type
.GetNotNullableType ();
1185 if (t
== typeof (bool))
1191 return t
.IsPrimitive
;
1194 internal static bool IsPrimitiveConversion (Type type
, Type target
)
1199 if (type
.IsNullable () && target
== type
.GetNotNullableType ())
1202 if (target
.IsNullable () && type
== target
.GetNotNullableType ())
1205 if (IsConvertiblePrimitive (type
) && IsConvertiblePrimitive (target
))
1211 internal static bool IsReferenceConversion (Type type
, Type target
)
1216 if (type
== typeof (object) || target
== typeof (object))
1219 if (type
.IsInterface
|| target
.IsInterface
)
1222 if (type
.IsValueType
|| target
.IsValueType
)
1225 if (type
.IsAssignableTo (target
) || target
.IsAssignableTo (type
))
1231 public static UnaryExpression
Convert (Expression expression
, Type type
)
1233 return Convert (expression
, type
, null);
1236 static MethodInfo
GetUserConversionMethod (Type type
, Type target
)
1238 var method
= GetUnaryOperator ("op_Explicit", type
, type
, target
);
1240 method
= GetUnaryOperator ("op_Implicit", type
, type
, target
);
1242 method
= GetUnaryOperator ("op_Explicit", target
, type
, target
);
1244 method
= GetUnaryOperator ("op_Implicit", target
, type
, target
);
1246 throw new InvalidOperationException ();
1251 public static UnaryExpression
Convert (Expression expression
, Type type
, MethodInfo method
)
1253 if (expression
== null)
1254 throw new ArgumentNullException ("expression");
1256 throw new ArgumentNullException ("type");
1258 var et
= expression
.Type
;
1261 CheckUnaryMethod (method
, et
);
1262 else if (!IsPrimitiveConversion (et
, type
) && !IsReferenceConversion (et
, type
))
1263 method
= GetUserConversionMethod (et
, type
);
1265 return new UnaryExpression (ExpressionType
.Convert
,
1266 expression
, type
, method
,
1267 IsConvertNodeLifted (method
, expression
, type
));
1270 static bool IsConvertNodeLifted (MethodInfo method
, Expression operand
, Type target
)
1273 return operand
.Type
.IsNullable () || target
.IsNullable ();
1275 if (operand
.Type
.IsNullable () && !ParameterMatch (method
, operand
.Type
))
1278 if (target
.IsNullable () && !ReturnTypeMatch (method
, target
))
1284 static bool ParameterMatch (MethodInfo method
, Type type
)
1286 return method
.GetParameters () [0].ParameterType
== type
;
1289 static bool ReturnTypeMatch (MethodInfo method
, Type type
)
1291 return method
.ReturnType
== type
;
1294 public static UnaryExpression
ConvertChecked (Expression expression
, Type type
)
1296 return ConvertChecked (expression
, type
, null);
1299 public static UnaryExpression
ConvertChecked (Expression expression
, Type type
, MethodInfo method
)
1301 if (expression
== null)
1302 throw new ArgumentNullException ("expression");
1304 throw new ArgumentNullException ("type");
1306 var et
= expression
.Type
;
1309 CheckUnaryMethod (method
, et
);
1310 else if (IsReferenceConversion (et
, type
))
1311 return Convert (expression
, type
, method
);
1312 else if (!IsPrimitiveConversion (et
, type
))
1313 method
= GetUserConversionMethod (et
, type
);
1315 return new UnaryExpression (ExpressionType
.ConvertChecked
,
1316 expression
, type
, method
,
1317 IsConvertNodeLifted (method
, expression
, type
));
1320 public static ElementInit
ElementInit (MethodInfo addMethod
, params Expression
[] arguments
)
1322 return ElementInit (addMethod
, arguments
as IEnumerable
<Expression
>);
1325 public static ElementInit
ElementInit (MethodInfo addMethod
, IEnumerable
<Expression
> arguments
)
1327 if (addMethod
== null)
1328 throw new ArgumentNullException ("addMethod");
1329 if (arguments
== null)
1330 throw new ArgumentNullException ("arguments");
1331 if (addMethod
.Name
.ToLower (CultureInfo
.InvariantCulture
) != "add")
1332 throw new ArgumentException ("addMethod");
1333 if (addMethod
.IsStatic
)
1334 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1336 var args
= CheckMethodArguments (addMethod
, arguments
);
1338 return new ElementInit (addMethod
, args
);
1341 public static MemberExpression
Field (Expression expression
, FieldInfo field
)
1344 throw new ArgumentNullException ("field");
1345 if (!field
.IsStatic
) {
1346 if (expression
== null)
1347 throw new ArgumentNullException ("expression");
1348 if (!expression
.Type
.IsAssignableTo (field
.DeclaringType
))
1349 throw new ArgumentException ("field");
1350 } else if (expression
!= null)
1351 throw new ArgumentException ("expression");
1353 return new MemberExpression (expression
, field
, field
.FieldType
);
1356 public static MemberExpression
Field (Expression expression
, string fieldName
)
1358 if (expression
== null)
1359 throw new ArgumentNullException ("expression");
1361 var field
= expression
.Type
.GetField (fieldName
, AllInstance
);
1363 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName
, expression
.Type
));
1365 return new MemberExpression (expression
, field
, field
.FieldType
);
1368 public static Type
GetActionType (params Type
[] typeArgs
)
1370 if (typeArgs
== null)
1371 throw new ArgumentNullException ("typeArgs");
1373 if (typeArgs
.Length
> 4)
1374 throw new ArgumentException ("No Action type of this arity");
1376 if (typeArgs
.Length
== 0)
1377 return typeof (Action
);
1380 switch (typeArgs
.Length
) {
1382 action
= typeof (Action
<>);
1385 action
= typeof (Action
<,>);
1388 action
= typeof (Action
<,,>);
1391 action
= typeof (Action
<,,,>);
1395 return action
.MakeGenericType (typeArgs
);
1398 public static Type
GetFuncType (params Type
[] typeArgs
)
1400 if (typeArgs
== null)
1401 throw new ArgumentNullException ("typeArgs");
1403 if (typeArgs
.Length
< 1 || typeArgs
.Length
> 5)
1404 throw new ArgumentException ("No Func type of this arity");
1407 switch (typeArgs
.Length
) {
1409 func
= typeof (Func
<>);
1412 func
= typeof (Func
<,>);
1415 func
= typeof (Func
<,,>);
1418 func
= typeof (Func
<,,,>);
1421 func
= typeof (Func
<,,,,>);
1425 return func
.MakeGenericType (typeArgs
);
1428 public static InvocationExpression
Invoke (Expression expression
, params Expression
[] arguments
)
1430 return Invoke (expression
, arguments
as IEnumerable
<Expression
>);
1433 static Type
GetInvokableType (Type t
)
1435 if (t
.IsAssignableTo (typeof (Delegate
)))
1438 return GetGenericType (t
, typeof (Expression
<>));
1441 static Type
GetGenericType (Type t
, Type def
)
1446 if (t
.IsGenericType
&& t
.GetGenericTypeDefinition () == def
)
1449 return GetGenericType (t
.BaseType
, def
);
1452 public static InvocationExpression
Invoke (Expression expression
, IEnumerable
<Expression
> arguments
)
1454 if (expression
== null)
1455 throw new ArgumentNullException ("expression");
1457 var type
= GetInvokableType (expression
.Type
);
1459 throw new ArgumentException ("The type of the expression is not invokable");
1461 var args
= arguments
.ToReadOnlyCollection ();
1462 CheckForNull (args
, "arguments");
1464 var invoke
= type
.GetInvokeMethod ();
1466 throw new ArgumentException ("expression");
1468 if (invoke
.GetParameters ().Length
!= args
.Count
)
1469 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1471 args
= CheckMethodArguments (invoke
, args
);
1473 return new InvocationExpression (expression
, invoke
.ReturnType
, args
);
1476 static bool CanAssign (Type target
, Type source
)
1478 // This catches object and value type mixage, type compatibility is handled later
1479 if (target
.IsValueType ^ source
.IsValueType
)
1482 return source
.IsAssignableTo (target
);
1485 static Expression
CheckLambda (Type delegateType
, Expression body
, ReadOnlyCollection
<ParameterExpression
> parameters
)
1487 if (!delegateType
.IsSubclassOf (typeof (System
.Delegate
)))
1488 throw new ArgumentException ("delegateType");
1490 var invoke
= delegateType
.GetInvokeMethod ();
1492 throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
1494 var invoke_parameters
= invoke
.GetParameters ();
1495 if (invoke_parameters
.Length
!= parameters
.Count
)
1496 throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType
), "delegateType");
1498 for (int i
= 0; i
< invoke_parameters
.Length
; i
++) {
1499 var parameter
= parameters
[i
];
1500 if (parameter
== null)
1501 throw new ArgumentNullException ("parameters");
1503 if (!CanAssign (parameter
.Type
, invoke_parameters
[i
].ParameterType
))
1504 throw new ArgumentException (String
.Format ("Can not assign a {0} to a {1}", invoke_parameters
[i
].ParameterType
, parameter
.Type
));
1507 if (invoke
.ReturnType
!= typeof (void)) {
1508 if (!CanAssign (invoke
.ReturnType
, body
.Type
)) {
1509 if (invoke
.ReturnType
.IsExpression ())
1510 return Expression
.Quote (body
);
1512 throw new ArgumentException (String
.Format ("body type {0} can not be assigned to {1}", body
.Type
, invoke
.ReturnType
));
1518 public static Expression
<TDelegate
> Lambda
<TDelegate
> (Expression body
, params ParameterExpression
[] parameters
)
1520 return Lambda
<TDelegate
> (body
, parameters
as IEnumerable
<ParameterExpression
>);
1523 public static Expression
<TDelegate
> Lambda
<TDelegate
> (Expression body
, IEnumerable
<ParameterExpression
> parameters
)
1526 throw new ArgumentNullException ("body");
1528 var ps
= parameters
.ToReadOnlyCollection ();
1530 body
= CheckLambda (typeof (TDelegate
), body
, ps
);
1532 return new Expression
<TDelegate
> (body
, ps
);
1535 public static LambdaExpression
Lambda (Expression body
, params ParameterExpression
[] parameters
)
1538 throw new ArgumentNullException ("body");
1539 if (parameters
.Length
> 4)
1540 throw new ArgumentException ("Too many parameters");
1542 return Lambda (GetDelegateType (body
.Type
, parameters
), body
, parameters
);
1545 static Type
GetDelegateType (Type return_type
, ParameterExpression
[] parameters
)
1547 if (parameters
== null)
1548 parameters
= new ParameterExpression
[0];
1550 if (return_type
== typeof (void))
1551 return GetActionType (parameters
.Select (p
=> p
.Type
).ToArray ());
1553 var types
= new Type
[parameters
.Length
+ 1];
1554 for (int i
= 0; i
< types
.Length
- 1; i
++)
1555 types
[i
] = parameters
[i
].Type
;
1557 types
[types
.Length
- 1] = return_type
;
1558 return GetFuncType (types
);
1561 public static LambdaExpression
Lambda (Type delegateType
, Expression body
, params ParameterExpression
[] parameters
)
1563 return Lambda (delegateType
, body
, parameters
as IEnumerable
<ParameterExpression
>);
1566 static LambdaExpression
CreateExpressionOf (Type type
, Expression body
, ReadOnlyCollection
<ParameterExpression
> parameters
)
1568 return (LambdaExpression
) typeof (Expression
<>).MakeGenericType (type
).GetConstructor (
1569 NonPublicInstance
, null, new [] { typeof (Expression), typeof (ReadOnlyCollection<ParameterExpression>) }
, null).Invoke (new object [] { body, parameters }
);
1572 public static LambdaExpression
Lambda (Type delegateType
, Expression body
, IEnumerable
<ParameterExpression
> parameters
)
1574 if (delegateType
== null)
1575 throw new ArgumentNullException ("delegateType");
1577 throw new ArgumentNullException ("body");
1579 var ps
= parameters
.ToReadOnlyCollection ();
1581 body
= CheckLambda (delegateType
, body
, ps
);
1583 return CreateExpressionOf (delegateType
, body
, ps
);
1586 public static MemberListBinding
ListBind (MemberInfo member
, params ElementInit
[] initializers
)
1588 return ListBind (member
, initializers
as IEnumerable
<ElementInit
>);
1591 static void CheckIsAssignableToIEnumerable (Type t
)
1593 if (!t
.IsAssignableTo (typeof (IEnumerable
)))
1594 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t
));
1597 public static MemberListBinding
ListBind (MemberInfo member
, IEnumerable
<ElementInit
> initializers
)
1600 throw new ArgumentNullException ("member");
1601 if (initializers
== null)
1602 throw new ArgumentNullException ("initializers");
1604 var inits
= initializers
.ToReadOnlyCollection ();
1605 CheckForNull (inits
, "initializers");
1607 member
.OnFieldOrProperty (
1608 field
=> CheckIsAssignableToIEnumerable (field
.FieldType
),
1609 prop
=> CheckIsAssignableToIEnumerable (prop
.PropertyType
));
1611 return new MemberListBinding (member
, inits
);
1614 public static MemberListBinding
ListBind (MethodInfo propertyAccessor
, params ElementInit
[] initializers
)
1616 return ListBind (propertyAccessor
, initializers
as IEnumerable
<ElementInit
>);
1619 static void CheckForNull
<T
> (ReadOnlyCollection
<T
> collection
, string name
) where T
: class
1621 foreach (var t
in collection
)
1623 throw new ArgumentNullException (name
);
1626 public static MemberListBinding
ListBind (MethodInfo propertyAccessor
, IEnumerable
<ElementInit
> initializers
)
1628 if (propertyAccessor
== null)
1629 throw new ArgumentNullException ("propertyAccessor");
1630 if (initializers
== null)
1631 throw new ArgumentNullException ("initializers");
1633 var inits
= initializers
.ToReadOnlyCollection ();
1634 CheckForNull (inits
, "initializers");
1636 var prop
= GetAssociatedProperty (propertyAccessor
);
1638 throw new ArgumentException ("propertyAccessor");
1640 CheckIsAssignableToIEnumerable (prop
.PropertyType
);
1642 return new MemberListBinding (prop
, inits
);
1645 public static ListInitExpression
ListInit (NewExpression newExpression
, params ElementInit
[] initializers
)
1647 return ListInit (newExpression
, initializers
as IEnumerable
<ElementInit
>);
1650 public static ListInitExpression
ListInit (NewExpression newExpression
, IEnumerable
<ElementInit
> initializers
)
1652 var inits
= CheckListInit (newExpression
, initializers
);
1654 return new ListInitExpression (newExpression
, inits
);
1657 public static ListInitExpression
ListInit (NewExpression newExpression
, params Expression
[] initializers
)
1659 return ListInit (newExpression
, initializers
as IEnumerable
<Expression
>);
1662 public static ListInitExpression
ListInit (NewExpression newExpression
, IEnumerable
<Expression
> initializers
)
1664 var inits
= CheckListInit (newExpression
, initializers
);
1666 var add_method
= GetAddMethod (newExpression
.Type
, inits
[0].Type
);
1667 if (add_method
== null)
1668 throw new InvalidOperationException ("No suitable add method found");
1670 return new ListInitExpression (newExpression
, CreateInitializers (add_method
, inits
));
1673 static ReadOnlyCollection
<ElementInit
> CreateInitializers (MethodInfo add_method
, ReadOnlyCollection
<Expression
> initializers
)
1675 return (from init
in initializers
select Expression
.ElementInit (add_method
, init
)).ToReadOnlyCollection ();
1678 static MethodInfo
GetAddMethod (Type type
, Type arg
)
1680 return type
.GetMethod ("Add", PublicInstance
| BindingFlags
.IgnoreCase
, null, new [] { arg }
, null);
1683 public static ListInitExpression
ListInit (NewExpression newExpression
, MethodInfo addMethod
, params Expression
[] initializers
)
1685 return ListInit (newExpression
, addMethod
, initializers
as IEnumerable
<Expression
>);
1688 static ReadOnlyCollection
<T
> CheckListInit
<T
> (NewExpression newExpression
, IEnumerable
<T
> initializers
) where T
: class
1690 if (newExpression
== null)
1691 throw new ArgumentNullException ("newExpression");
1692 if (initializers
== null)
1693 throw new ArgumentNullException ("initializers");
1694 if (!newExpression
.Type
.IsAssignableTo (typeof (IEnumerable
)))
1695 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1697 var inits
= initializers
.ToReadOnlyCollection ();
1698 if (inits
.Count
== 0)
1699 throw new ArgumentException ("Empty initializers");
1701 CheckForNull (inits
, "initializers");
1706 public static ListInitExpression
ListInit (NewExpression newExpression
, MethodInfo addMethod
, IEnumerable
<Expression
> initializers
)
1708 var inits
= CheckListInit (newExpression
, initializers
);
1710 if (addMethod
!= null) {
1711 if (addMethod
.Name
.ToLower (CultureInfo
.InvariantCulture
) != "add")
1712 throw new ArgumentException ("addMethod");
1714 var parameters
= addMethod
.GetParameters ();
1715 if (parameters
.Length
!= 1)
1716 throw new ArgumentException ("addMethod");
1718 foreach (var expression
in inits
)
1719 if (!IsAssignableToParameterType (expression
.Type
, parameters
[0]))
1720 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1723 if (addMethod
== null)
1724 addMethod
= GetAddMethod (newExpression
.Type
, inits
[0].Type
);
1726 if (addMethod
== null)
1727 throw new InvalidOperationException ("No suitable add method found");
1729 return new ListInitExpression (newExpression
, CreateInitializers (addMethod
, inits
));
1732 public static MemberExpression
MakeMemberAccess (Expression expression
, MemberInfo member
)
1734 if (expression
== null)
1735 throw new ArgumentNullException ("expression");
1737 throw new ArgumentNullException ("member");
1739 var field
= member
as FieldInfo
;
1741 return Field (expression
, field
);
1743 var property
= member
as PropertyInfo
;
1744 if (property
!= null)
1745 return Property (expression
, property
);
1747 throw new ArgumentException ("Member should either be a field or a property");
1750 public static UnaryExpression
MakeUnary (ExpressionType unaryType
, Expression operand
, Type type
)
1752 return MakeUnary (unaryType
, operand
, type
, null);
1755 public static UnaryExpression
MakeUnary (ExpressionType unaryType
, Expression operand
, Type type
, MethodInfo method
)
1757 switch (unaryType
) {
1758 case ExpressionType
.ArrayLength
:
1759 return ArrayLength (operand
);
1760 case ExpressionType
.Convert
:
1761 return Convert (operand
, type
, method
);
1762 case ExpressionType
.ConvertChecked
:
1763 return ConvertChecked (operand
, type
, method
);
1764 case ExpressionType
.Negate
:
1765 return Negate (operand
, method
);
1766 case ExpressionType
.NegateChecked
:
1767 return NegateChecked (operand
, method
);
1768 case ExpressionType
.Not
:
1769 return Not (operand
, method
);
1770 case ExpressionType
.Quote
:
1771 return Quote (operand
);
1772 case ExpressionType
.TypeAs
:
1773 return TypeAs (operand
, type
);
1774 case ExpressionType
.UnaryPlus
:
1775 return UnaryPlus (operand
, method
);
1778 throw new ArgumentException ("MakeUnary expect an unary operator");
1781 public static MemberMemberBinding
MemberBind (MemberInfo member
, params MemberBinding
[] bindings
)
1783 return MemberBind (member
, bindings
as IEnumerable
<MemberBinding
>);
1786 public static MemberMemberBinding
MemberBind (MemberInfo member
, IEnumerable
<MemberBinding
> bindings
)
1789 throw new ArgumentNullException ("member");
1791 var type
= member
.OnFieldOrProperty (
1792 field
=> field
.FieldType
,
1793 prop
=> prop
.PropertyType
);
1795 return new MemberMemberBinding (member
, CheckMemberBindings (type
, bindings
));
1798 public static MemberMemberBinding
MemberBind (MethodInfo propertyAccessor
, params MemberBinding
[] bindings
)
1800 return MemberBind (propertyAccessor
, bindings
as IEnumerable
<MemberBinding
>);
1803 public static MemberMemberBinding
MemberBind (MethodInfo propertyAccessor
, IEnumerable
<MemberBinding
> bindings
)
1805 if (propertyAccessor
== null)
1806 throw new ArgumentNullException ("propertyAccessor");
1808 var bds
= bindings
.ToReadOnlyCollection ();
1809 CheckForNull (bds
, "bindings");
1811 var prop
= GetAssociatedProperty (propertyAccessor
);
1813 throw new ArgumentException ("propertyAccessor");
1815 return new MemberMemberBinding (prop
, CheckMemberBindings (prop
.PropertyType
, bindings
));
1818 static ReadOnlyCollection
<MemberBinding
> CheckMemberBindings (Type type
, IEnumerable
<MemberBinding
> bindings
)
1820 if (bindings
== null)
1821 throw new ArgumentNullException ("bindings");
1823 var bds
= bindings
.ToReadOnlyCollection ();
1824 CheckForNull (bds
, "bindings");
1826 foreach (var binding
in bds
)
1827 if (!type
.IsAssignableTo (binding
.Member
.DeclaringType
))
1828 throw new ArgumentException ("Type not assignable to member type");
1833 public static MemberInitExpression
MemberInit (NewExpression newExpression
, params MemberBinding
[] bindings
)
1835 return MemberInit (newExpression
, bindings
as IEnumerable
<MemberBinding
>);
1838 public static MemberInitExpression
MemberInit (NewExpression newExpression
, IEnumerable
<MemberBinding
> bindings
)
1840 if (newExpression
== null)
1841 throw new ArgumentNullException ("newExpression");
1843 return new MemberInitExpression (newExpression
, CheckMemberBindings (newExpression
.Type
, bindings
));
1846 public static UnaryExpression
Negate (Expression expression
)
1848 return Negate (expression
, null);
1851 public static UnaryExpression
Negate (Expression expression
, MethodInfo method
)
1853 method
= UnaryCoreCheck ("op_UnaryNegation", expression
, method
, type
=> IsSignedNumber (type
));
1855 return MakeSimpleUnary (ExpressionType
.Negate
, expression
, method
);
1858 public static UnaryExpression
NegateChecked (Expression expression
)
1860 return NegateChecked (expression
, null);
1863 public static UnaryExpression
NegateChecked (Expression expression
, MethodInfo method
)
1865 method
= UnaryCoreCheck ("op_UnaryNegation", expression
, method
, type
=> IsSignedNumber (type
));
1867 return MakeSimpleUnary (ExpressionType
.NegateChecked
, expression
, method
);
1870 public static NewExpression
New (ConstructorInfo constructor
)
1872 if (constructor
== null)
1873 throw new ArgumentNullException ("constructor");
1875 if (constructor
.GetParameters ().Length
> 0)
1876 throw new ArgumentException ("Constructor must be parameter less");
1878 return new NewExpression (constructor
, (null as IEnumerable
<Expression
>).ToReadOnlyCollection (), null);
1881 public static NewExpression
New (Type type
)
1884 throw new ArgumentNullException ("type");
1886 CheckNotVoid (type
);
1888 var args
= (null as IEnumerable
<Expression
>).ToReadOnlyCollection ();
1890 if (type
.IsValueType
)
1891 return new NewExpression (type
, args
);
1893 var ctor
= type
.GetConstructor (Type
.EmptyTypes
);
1895 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1897 return new NewExpression (ctor
, args
, null);
1900 public static NewExpression
New (ConstructorInfo constructor
, params Expression
[] arguments
)
1902 return New (constructor
, arguments
as IEnumerable
<Expression
>);
1905 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
)
1907 if (constructor
== null)
1908 throw new ArgumentNullException ("constructor");
1910 var args
= CheckMethodArguments (constructor
, arguments
);
1912 return new NewExpression (constructor
, args
, null);
1915 static IList
<Expression
> CreateArgumentList (IEnumerable
<Expression
> arguments
)
1917 if (arguments
== null)
1918 return arguments
.ToReadOnlyCollection ();
1920 return arguments
.ToList ();
1923 static void CheckNonGenericMethod (MethodBase method
)
1925 if (method
.IsGenericMethodDefinition
|| method
.ContainsGenericParameters
)
1926 throw new ArgumentException ("Can not used open generic methods");
1929 static ReadOnlyCollection
<Expression
> CheckMethodArguments (MethodBase method
, IEnumerable
<Expression
> args
)
1931 CheckNonGenericMethod (method
);
1933 var arguments
= CreateArgumentList (args
);
1934 var parameters
= method
.GetParameters ();
1936 if (arguments
.Count
!= parameters
.Length
)
1937 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1939 for (int i
= 0; i
< parameters
.Length
; i
++) {
1940 if (arguments
[i
] == null)
1941 throw new ArgumentNullException ("arguments");
1943 if (!IsAssignableToParameterType (arguments
[i
].Type
, parameters
[i
])) {
1944 if (!parameters
[i
].ParameterType
.IsExpression ())
1945 throw new ArgumentException ("arguments");
1947 arguments
[i
] = Expression
.Quote (arguments
[i
]);
1951 return arguments
.ToReadOnlyCollection ();
1954 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
, params MemberInfo
[] members
)
1956 return New (constructor
, arguments
, members
as IEnumerable
<MemberInfo
>);
1959 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
, IEnumerable
<MemberInfo
> members
)
1961 if (constructor
== null)
1962 throw new ArgumentNullException ("constructor");
1964 var args
= arguments
.ToReadOnlyCollection ();
1965 var mmbs
= members
.ToReadOnlyCollection ();
1967 CheckForNull (args
, "arguments");
1968 CheckForNull (mmbs
, "members");
1970 args
= CheckMethodArguments (constructor
, arguments
);
1972 if (args
.Count
!= mmbs
.Count
)
1973 throw new ArgumentException ("Arguments count does not match members count");
1975 for (int i
= 0; i
< mmbs
.Count
; i
++) {
1976 var member
= mmbs
[i
];
1978 switch (member
.MemberType
) {
1979 case MemberTypes
.Field
:
1980 type
= (member
as FieldInfo
).FieldType
;
1982 case MemberTypes
.Method
:
1983 type
= (member
as MethodInfo
).ReturnType
;
1985 case MemberTypes
.Property
:
1986 var prop
= member
as PropertyInfo
;
1987 if (prop
.GetGetMethod (true) == null)
1988 throw new ArgumentException ("Property must have a getter");
1990 type
= (member
as PropertyInfo
).PropertyType
;
1993 throw new ArgumentException ("Member type not allowed");
1996 if (!args
[i
].Type
.IsAssignableTo (type
))
1997 throw new ArgumentException ("Argument type not assignable to member type");
2000 return new NewExpression (constructor
, args
, mmbs
);
2003 public static NewArrayExpression
NewArrayBounds (Type type
, params Expression
[] bounds
)
2005 return NewArrayBounds (type
, bounds
as IEnumerable
<Expression
>);
2008 public static NewArrayExpression
NewArrayBounds (Type type
, IEnumerable
<Expression
> bounds
)
2011 throw new ArgumentNullException ("type");
2013 throw new ArgumentNullException ("bounds");
2015 CheckNotVoid (type
);
2017 var array_bounds
= bounds
.ToReadOnlyCollection ();
2018 foreach (var expression
in array_bounds
)
2019 if (!IsInt (expression
.Type
))
2020 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
2022 return new NewArrayExpression (ExpressionType
.NewArrayBounds
, type
.MakeArrayType (array_bounds
.Count
), array_bounds
);
2025 public static NewArrayExpression
NewArrayInit (Type type
, params Expression
[] initializers
)
2027 return NewArrayInit (type
, initializers
as IEnumerable
<Expression
>);
2030 public static NewArrayExpression
NewArrayInit (Type type
, IEnumerable
<Expression
> initializers
)
2033 throw new ArgumentNullException ("type");
2034 if (initializers
== null)
2035 throw new ArgumentNullException ("initializers");
2037 CheckNotVoid (type
);
2039 var inits
= initializers
.ToReadOnlyCollection ();
2041 foreach (var expression
in inits
) {
2042 if (expression
== null)
2043 throw new ArgumentNullException ("initializers");
2045 if (!expression
.Type
.IsAssignableTo (type
))
2046 throw new InvalidOperationException (
2047 string.Format ("{0} IsAssignableTo {1}, expression [ {2} ] : {3}", expression
.Type
, type
, expression
.NodeType
, expression
));
2049 // TODO: Quote elements if type == typeof (Expression)
2052 return new NewArrayExpression (ExpressionType
.NewArrayInit
, type
.MakeArrayType (), inits
);
2055 public static UnaryExpression
Not (Expression expression
)
2057 return Not (expression
, null);
2060 public static UnaryExpression
Not (Expression expression
, MethodInfo method
)
2062 Func
<Type
, bool> validator
= type
=> IsIntOrBool (type
);
2064 method
= UnaryCoreCheck ("op_LogicalNot", expression
, method
, validator
);
2067 method
= UnaryCoreCheck ("op_OnesComplement", expression
, method
, validator
);
2069 return MakeSimpleUnary (ExpressionType
.Not
, expression
, method
);
2072 static void CheckNotVoid (Type type
)
2074 if (type
== typeof (void))
2075 throw new ArgumentException ("Type can't be void");
2078 public static ParameterExpression
Parameter (Type type
, string name
)
2081 throw new ArgumentNullException ("type");
2083 CheckNotVoid (type
);
2085 return new ParameterExpression (type
, name
);
2088 public static MemberExpression
Property (Expression expression
, MethodInfo propertyAccessor
)
2090 if (propertyAccessor
== null)
2091 throw new ArgumentNullException ("propertyAccessor");
2093 CheckNonGenericMethod (propertyAccessor
);
2095 if (!propertyAccessor
.IsStatic
) {
2096 if (expression
== null)
2097 throw new ArgumentNullException ("expression");
2098 if (!expression
.Type
.IsAssignableTo (propertyAccessor
.DeclaringType
))
2099 throw new ArgumentException ("expression");
2100 } else if (expression
!= null)
2101 throw new ArgumentException ("expression");
2103 var prop
= GetAssociatedProperty (propertyAccessor
);
2105 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor
));
2107 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2110 static PropertyInfo
GetAssociatedProperty (MethodInfo method
)
2115 foreach (var prop
in method
.DeclaringType
.GetProperties (All
)) {
2116 if (method
.Equals (prop
.GetGetMethod (true)))
2118 if (method
.Equals (prop
.GetSetMethod (true)))
2125 public static MemberExpression
Property (Expression expression
, PropertyInfo property
)
2127 if (property
== null)
2128 throw new ArgumentNullException ("property");
2130 var getter
= property
.GetGetMethod (true);
2132 throw new ArgumentException ("getter");
2134 if (!getter
.IsStatic
) {
2135 if (expression
== null)
2136 throw new ArgumentNullException ("expression");
2137 if (!expression
.Type
.IsAssignableTo (property
.DeclaringType
))
2138 throw new ArgumentException ("expression");
2139 } else if (expression
!= null)
2140 throw new ArgumentException ("expression");
2142 return new MemberExpression (expression
, property
, property
.PropertyType
);
2145 public static MemberExpression
Property (Expression expression
, string propertyName
)
2147 if (expression
== null)
2148 throw new ArgumentNullException ("expression");
2150 var prop
= expression
.Type
.GetProperty (propertyName
, AllInstance
);
2152 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName
, expression
.Type
));
2154 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2157 public static MemberExpression
PropertyOrField (Expression expression
, string propertyOrFieldName
)
2159 if (expression
== null)
2160 throw new ArgumentNullException ("expression");
2161 if (propertyOrFieldName
== null)
2162 throw new ArgumentNullException ("propertyOrFieldName");
2164 var prop
= expression
.Type
.GetProperty (propertyOrFieldName
, AllInstance
);
2166 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2168 var field
= expression
.Type
.GetField (propertyOrFieldName
, AllInstance
);
2170 return new MemberExpression (expression
, field
, field
.FieldType
);
2172 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName
, expression
.Type
));
2175 public static UnaryExpression
Quote (Expression expression
)
2177 if (expression
== null)
2178 throw new ArgumentNullException ("expression");
2180 return new UnaryExpression (ExpressionType
.Quote
, expression
, expression
.GetType ());
2183 public static UnaryExpression
TypeAs (Expression expression
, Type type
)
2185 if (expression
== null)
2186 throw new ArgumentNullException ("expression");
2188 throw new ArgumentNullException ("type");
2189 if (type
.IsValueType
&& !type
.IsNullable ())
2190 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
2192 return new UnaryExpression (ExpressionType
.TypeAs
, expression
, type
);
2195 public static TypeBinaryExpression
TypeIs (Expression expression
, Type type
)
2197 if (expression
== null)
2198 throw new ArgumentNullException ("expression");
2200 throw new ArgumentNullException ("type");
2202 CheckNotVoid (type
);
2204 return new TypeBinaryExpression (ExpressionType
.TypeIs
, expression
, type
, typeof (bool));
2207 public static UnaryExpression
UnaryPlus (Expression expression
)
2209 return UnaryPlus (expression
, null);
2212 public static UnaryExpression
UnaryPlus (Expression expression
, MethodInfo method
)
2214 method
= UnaryCoreCheck ("op_UnaryPlus", expression
, method
, type
=> IsNumber (type
));
2216 return MakeSimpleUnary (ExpressionType
.UnaryPlus
, expression
, method
);
2219 static bool IsInt (Type t
)
2221 return t
== typeof (byte) || t
== typeof (sbyte) ||
2222 t
== typeof (short) || t
== typeof (ushort) ||
2223 t
== typeof (int) || t
== typeof (uint) ||
2224 t
== typeof (long) || t
== typeof (ulong);
2227 static bool IsIntOrBool (Type t
)
2229 return IsInt (t
) || t
== typeof (bool);
2232 static bool IsNumber (Type t
)
2237 return t
== typeof (float) || t
== typeof (double);
2240 static bool IsSignedNumber (Type t
)
2242 return IsNumber (t
) && !IsUnsigned (t
);
2245 internal static bool IsUnsigned (Type t
)
2249 return IsUnsigned (t
.GetElementType ());
2252 return t
== typeof (ushort) ||
2253 t
== typeof (uint) ||
2254 t
== typeof (ulong) ||
2259 // This method must be overwritten by derived classes to
2260 // compile the expression
2262 internal virtual void Emit (EmitContext ec
)
2264 throw new NotImplementedException (String
.Format ("Emit method is not implemented in expression type {0}", GetType ()));