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
== typeof (bool))
272 if (oper_name
== "op_LeftShift" || oper_name
== "op_RightShift") {
273 if (IsInt (ultype
) && urtype
== typeof (int))
277 throw new InvalidOperationException (
278 String
.Format ("Operation {0} not defined for {1} and {2}", oper_name
!= null ? oper_name
.Substring (3) : "is", ltype
, rtype
));
283 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
284 // only ints and bools are allowed
286 static MethodInfo
BinaryBitwiseCoreCheck (string oper_name
, Expression left
, Expression right
, MethodInfo method
)
289 throw new ArgumentNullException ("left");
291 throw new ArgumentNullException ("right");
293 if (method
== null) {
294 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
295 if (left
.Type
== right
.Type
&& IsIntOrBool (left
.Type
))
299 method
= BinaryCoreCheck (oper_name
, left
, right
, method
);
300 if (method
== null) {
301 // The check in BinaryCoreCheck allows a bit more than we do
302 // (floats and doubles). Catch this here
303 if (left
.Type
== typeof (double) || left
.Type
== typeof (float))
304 throw new InvalidOperationException ("Types not supported");
310 static BinaryExpression
MakeSimpleBinary (ExpressionType et
, Expression left
, Expression right
, MethodInfo method
)
315 if (method
== null) {
316 is_lifted
= left
.Type
.IsNullable ();
319 var parameters
= method
.GetParameters ();
321 var lp
= parameters
[0];
322 var rp
= parameters
[1];
324 if (IsAssignableToOperatorParameter (left
, lp
) && IsAssignableToOperatorParameter (right
, rp
)) {
326 type
= method
.ReturnType
;
327 } else if (left
.Type
.IsNullable ()
328 && right
.Type
.IsNullable ()
329 && left
.Type
.GetNotNullableType () == lp
.ParameterType
330 && right
.Type
.GetNotNullableType () == rp
.ParameterType
331 && !method
.ReturnType
.IsNullable ()) {
334 type
= method
.ReturnType
.MakeNullableType ();
336 throw new InvalidOperationException ();
339 return new BinaryExpression (et
, type
, left
, right
, is_lifted
, is_lifted
, method
, null);
342 static bool IsAssignableToOperatorParameter (Expression expression
, ParameterInfo parameter
)
344 if (expression
.Type
== parameter
.ParameterType
)
347 if ((!expression
.Type
.IsNullable () && !parameter
.ParameterType
.IsNullable ())
348 && IsAssignableToParameterType (expression
.Type
, parameter
))
354 static UnaryExpression
MakeSimpleUnary (ExpressionType et
, Expression expression
, MethodInfo method
)
359 if (method
== null) {
360 type
= expression
.Type
;
361 is_lifted
= type
.IsNullable ();
363 var parameter
= method
.GetParameters () [0];
365 if (IsAssignableToOperatorParameter (expression
, parameter
)) {
367 type
= method
.ReturnType
;
368 } else if (expression
.Type
.IsNullable ()
369 && expression
.Type
.GetNotNullableType () == parameter
.ParameterType
370 && !method
.ReturnType
.IsNullable ()) {
373 type
= method
.ReturnType
.MakeNullableType ();
375 throw new InvalidOperationException ();
378 return new UnaryExpression (et
, expression
, type
, method
, is_lifted
);
381 static BinaryExpression
MakeBoolBinary (ExpressionType et
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
386 if (method
== null) {
387 if (!left
.Type
.IsNullable () && !right
.Type
.IsNullable ()) {
390 type
= typeof (bool);
391 } else if (left
.Type
.IsNullable () && right
.Type
.IsNullable ()) {
393 type
= liftToNull
? typeof (bool?) : typeof (bool);
395 throw new InvalidOperationException ();
397 var parameters
= method
.GetParameters ();
399 var lp
= parameters
[0];
400 var rp
= parameters
[1];
402 if (IsAssignableToOperatorParameter (left
, lp
) && IsAssignableToOperatorParameter (right
, rp
)) {
405 type
= method
.ReturnType
;
406 } else if (left
.Type
.IsNullable ()
407 && right
.Type
.IsNullable ()
408 && left
.Type
.GetNotNullableType () == lp
.ParameterType
409 && right
.Type
.GetNotNullableType () == rp
.ParameterType
) {
413 if (method
.ReturnType
== typeof (bool))
414 type
= liftToNull
? typeof (bool?) : typeof (bool);
415 else if (!method
.ReturnType
.IsNullable ()) {
417 // This behavior is not documented: what
418 // happens if the result is not typeof(bool), but
419 // the parameters are nullable: the result
420 // becomes nullable<returntype>
423 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
425 type
= method
.ReturnType
.MakeNullableType ();
427 throw new InvalidOperationException ();
429 throw new InvalidOperationException ();
432 return new BinaryExpression (et
, type
, left
, right
, liftToNull
, is_lifted
, method
, null);
438 public static BinaryExpression
Add (Expression left
, Expression right
)
440 return Add (left
, right
, null);
443 public static BinaryExpression
Add (Expression left
, Expression right
, MethodInfo method
)
445 method
= BinaryCoreCheck ("op_Addition", left
, right
, method
);
447 return MakeSimpleBinary (ExpressionType
.Add
, left
, right
, method
);
450 public static BinaryExpression
AddChecked (Expression left
, Expression right
)
452 return AddChecked (left
, right
, null);
455 public static BinaryExpression
AddChecked (Expression left
, Expression right
, MethodInfo method
)
457 method
= BinaryCoreCheck ("op_Addition", left
, right
, method
);
459 // The check in BinaryCoreCheck allows a bit more than we do
460 // (byte, sbyte). Catch that here
461 if (method
== null) {
462 if (left
.Type
== typeof (byte) || left
.Type
== typeof (sbyte))
463 throw new InvalidOperationException (String
.Format ("AddChecked not defined for {0} and {1}", left
.Type
, right
.Type
));
466 return MakeSimpleBinary (ExpressionType
.AddChecked
, left
, right
, method
);
469 public static BinaryExpression
Subtract (Expression left
, Expression right
)
471 return Subtract (left
, right
, null);
474 public static BinaryExpression
Subtract (Expression left
, Expression right
, MethodInfo method
)
476 method
= BinaryCoreCheck ("op_Subtraction", left
, right
, method
);
478 return MakeSimpleBinary (ExpressionType
.Subtract
, left
, right
, method
);
481 public static BinaryExpression
SubtractChecked (Expression left
, Expression right
)
483 return SubtractChecked (left
, right
, null);
486 public static BinaryExpression
SubtractChecked (Expression left
, Expression right
, MethodInfo method
)
488 method
= BinaryCoreCheck ("op_Subtraction", left
, right
, method
);
490 // The check in BinaryCoreCheck allows a bit more than we do
491 // (byte, sbyte). Catch that here
492 if (method
== null) {
493 if (left
.Type
== typeof (byte) || left
.Type
== typeof (sbyte))
494 throw new InvalidOperationException (String
.Format ("SubtractChecked not defined for {0} and {1}", left
.Type
, right
.Type
));
497 return MakeSimpleBinary (ExpressionType
.SubtractChecked
, left
, right
, method
);
500 public static BinaryExpression
Modulo (Expression left
, Expression right
)
502 return Modulo (left
, right
, null);
505 public static BinaryExpression
Modulo (Expression left
, Expression right
, MethodInfo method
)
507 method
= BinaryCoreCheck ("op_Modulus", left
, right
, method
);
509 return MakeSimpleBinary (ExpressionType
.Modulo
, left
, right
, method
);
512 public static BinaryExpression
Multiply (Expression left
, Expression right
)
514 return Multiply (left
, right
, null);
517 public static BinaryExpression
Multiply (Expression left
, Expression right
, MethodInfo method
)
519 method
= BinaryCoreCheck ("op_Multiply", left
, right
, method
);
521 return MakeSimpleBinary (ExpressionType
.Multiply
, left
, right
, method
);
524 public static BinaryExpression
MultiplyChecked (Expression left
, Expression right
)
526 return MultiplyChecked (left
, right
, null);
529 public static BinaryExpression
MultiplyChecked (Expression left
, Expression right
, MethodInfo method
)
531 method
= BinaryCoreCheck ("op_Multiply", left
, right
, method
);
533 return MakeSimpleBinary (ExpressionType
.MultiplyChecked
, left
, right
, method
);
536 public static BinaryExpression
Divide (Expression left
, Expression right
)
538 return Divide (left
, right
, null);
541 public static BinaryExpression
Divide (Expression left
, Expression right
, MethodInfo method
)
543 method
= BinaryCoreCheck ("op_Division", left
, right
, method
);
545 return MakeSimpleBinary (ExpressionType
.Divide
, left
, right
, method
);
548 public static BinaryExpression
Power (Expression left
, Expression right
)
550 return Power (left
, right
, null);
553 public static BinaryExpression
Power (Expression left
, Expression right
, MethodInfo method
)
555 method
= BinaryCoreCheck (null, left
, right
, method
);
557 if (left
.Type
.GetNotNullableType () != typeof (double))
558 throw new InvalidOperationException ("Power only supports double arguments");
560 return MakeSimpleBinary (ExpressionType
.Power
, left
, right
, method
);
566 public static BinaryExpression
And (Expression left
, Expression right
)
568 return And (left
, right
, null);
571 public static BinaryExpression
And (Expression left
, Expression right
, MethodInfo method
)
573 method
= BinaryBitwiseCoreCheck ("op_BitwiseAnd", left
, right
, method
);
575 return MakeSimpleBinary (ExpressionType
.And
, left
, right
, method
);
578 public static BinaryExpression
Or (Expression left
, Expression right
)
580 return Or (left
, right
, null);
583 public static BinaryExpression
Or (Expression left
, Expression right
, MethodInfo method
)
585 method
= BinaryBitwiseCoreCheck ("op_BitwiseOr", left
, right
, method
);
587 return MakeSimpleBinary (ExpressionType
.Or
, left
, right
, method
);
590 public static BinaryExpression
ExclusiveOr (Expression left
, Expression right
)
592 return ExclusiveOr (left
, right
, null);
595 public static BinaryExpression
ExclusiveOr (Expression left
, Expression right
, MethodInfo method
)
597 method
= BinaryBitwiseCoreCheck ("op_ExclusiveOr", left
, right
, method
);
599 return MakeSimpleBinary (ExpressionType
.ExclusiveOr
, left
, right
, method
);
602 public static BinaryExpression
LeftShift (Expression left
, Expression right
)
604 return LeftShift (left
, right
, null);
607 public static BinaryExpression
LeftShift (Expression left
, Expression right
, MethodInfo method
)
609 method
= BinaryBitwiseCoreCheck ("op_LeftShift", left
, right
, method
);
611 return MakeSimpleBinary (ExpressionType
.LeftShift
, left
, right
, method
);
614 public static BinaryExpression
RightShift (Expression left
, Expression right
)
616 return RightShift (left
, right
, null);
619 public static BinaryExpression
RightShift (Expression left
, Expression right
, MethodInfo method
)
621 method
= BinaryCoreCheck ("op_RightShift", left
, right
, method
);
623 return MakeSimpleBinary (ExpressionType
.RightShift
, left
, right
, method
);
629 public static BinaryExpression
AndAlso (Expression left
, Expression right
)
631 return AndAlso (left
, right
, null);
634 public static BinaryExpression
AndAlso (Expression left
, Expression right
, MethodInfo method
)
636 method
= ConditionalBinaryCheck ("op_BitwiseAnd", left
, right
, method
);
638 return MakeBoolBinary (ExpressionType
.AndAlso
, left
, right
, true, method
);
641 static MethodInfo
ConditionalBinaryCheck (string oper
, Expression left
, Expression right
, MethodInfo method
)
643 method
= BinaryCoreCheck (oper
, left
, right
, method
);
645 if (method
== null) {
646 if (left
.Type
.GetNotNullableType () != typeof (bool))
647 throw new InvalidOperationException ("Only booleans are allowed");
649 var type
= left
.Type
.GetNotNullableType ();
651 // The method should have identical parameter and return types.
652 if (left
.Type
!= right
.Type
|| method
.ReturnType
!= type
)
653 throw new ArgumentException ("left, right and return type must match");
655 var optrue
= GetTrueOperator (type
);
656 var opfalse
= GetFalseOperator (type
);
658 if (optrue
== null || opfalse
== null)
659 throw new ArgumentException ("Operators true and false are required but not defined");
665 public static BinaryExpression
OrElse (Expression left
, Expression right
)
667 return OrElse (left
, right
, null);
670 public static BinaryExpression
OrElse (Expression left
, Expression right
, MethodInfo method
)
672 method
= ConditionalBinaryCheck ("op_BitwiseOr", left
, right
, method
);
674 return MakeBoolBinary (ExpressionType
.OrElse
, left
, right
, true, method
);
680 public static BinaryExpression
Equal (Expression left
, Expression right
)
682 return Equal (left
, right
, false, null);
685 public static BinaryExpression
Equal (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
687 method
= BinaryCoreCheck ("op_Equality", left
, right
, method
);
689 return MakeBoolBinary (ExpressionType
.Equal
, left
, right
, liftToNull
, method
);
692 public static BinaryExpression
NotEqual (Expression left
, Expression right
)
694 return NotEqual (left
, right
, false, null);
698 public static BinaryExpression
NotEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
700 method
= BinaryCoreCheck ("op_Inequality", left
, right
, method
);
702 return MakeBoolBinary (ExpressionType
.NotEqual
, left
, right
, liftToNull
, method
);
705 public static BinaryExpression
GreaterThan (Expression left
, Expression right
)
707 return GreaterThan (left
, right
, false, null);
710 public static BinaryExpression
GreaterThan (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
712 method
= BinaryCoreCheck ("op_GreaterThan", left
, right
, method
);
714 return MakeBoolBinary (ExpressionType
.GreaterThan
, left
, right
, liftToNull
, method
);
717 public static BinaryExpression
GreaterThanOrEqual (Expression left
, Expression right
)
719 return GreaterThanOrEqual (left
, right
, false, null);
723 public static BinaryExpression
GreaterThanOrEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
725 method
= BinaryCoreCheck ("op_GreaterThanOrEqual", left
, right
, method
);
727 return MakeBoolBinary (ExpressionType
.GreaterThanOrEqual
, left
, right
, liftToNull
, method
);
730 public static BinaryExpression
LessThan (Expression left
, Expression right
)
732 return LessThan (left
, right
, false, null);
735 public static BinaryExpression
LessThan (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
737 method
= BinaryCoreCheck ("op_LessThan", left
, right
, method
);
739 return MakeBoolBinary (ExpressionType
.LessThan
, left
, right
, liftToNull
, method
);
742 public static BinaryExpression
LessThanOrEqual (Expression left
, Expression right
)
744 return LessThanOrEqual (left
, right
, false, null);
747 public static BinaryExpression
LessThanOrEqual (Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
749 method
= BinaryCoreCheck ("op_LessThanOrEqual", left
, right
, method
);
751 return MakeBoolBinary (ExpressionType
.LessThanOrEqual
, left
, right
, liftToNull
, method
);
758 static void CheckArray (Expression array
)
761 throw new ArgumentNullException ("array");
762 if (!array
.Type
.IsArray
)
763 throw new ArgumentException ("The array argument must be of type array");
766 public static BinaryExpression
ArrayIndex (Expression array
, Expression index
)
771 throw new ArgumentNullException ("index");
772 if (array
.Type
.GetArrayRank () != 1)
773 throw new ArgumentException ("The array argument must be a single dimensional array");
774 if (index
.Type
!= typeof (int))
775 throw new ArgumentException ("The index must be of type int");
777 return new BinaryExpression (ExpressionType
.ArrayIndex
, array
.Type
.GetElementType (), array
, index
);
780 public static BinaryExpression
Coalesce (Expression left
, Expression right
)
782 return Coalesce (left
, right
, null);
785 static BinaryExpression
MakeCoalesce (Expression left
, Expression right
)
789 if (left
.Type
.IsNullable ()) {
790 Type lbase
= left
.Type
.GetNotNullableType ();
792 if (!right
.Type
.IsNullable () && right
.Type
.IsAssignableTo (lbase
))
796 if (result
== null && right
.Type
.IsAssignableTo (left
.Type
))
799 if (result
== null) {
800 if (left
.Type
.IsNullable () && left
.Type
.GetNotNullableType ().IsAssignableTo (right
.Type
))
805 throw new ArgumentException ("Incompatible argument types");
807 return new BinaryExpression (ExpressionType
.Coalesce
, result
, left
, right
, false, false, null, null);
810 static BinaryExpression
MakeConvertedCoalesce (Expression left
, Expression right
, LambdaExpression conversion
)
812 var invoke
= conversion
.Type
.GetInvokeMethod ();
814 CheckNotVoid (invoke
.ReturnType
);
816 if (invoke
.ReturnType
!= right
.Type
)
817 throw new InvalidOperationException ("Conversion return type doesn't march right type");
819 var parameters
= invoke
.GetParameters ();
821 if (parameters
.Length
!= 1)
822 throw new ArgumentException ("Conversion has wrong number of parameters");
824 if (!IsAssignableToParameterType (left
.Type
, parameters
[0]))
825 throw new InvalidOperationException ("Conversion argument doesn't marcht left type");
827 return new BinaryExpression (ExpressionType
.Coalesce
, right
.Type
, left
, right
, false, false, null, conversion
);
830 public static BinaryExpression
Coalesce (Expression left
, Expression right
, LambdaExpression conversion
)
833 throw new ArgumentNullException ("left");
835 throw new ArgumentNullException ("right");
838 // First arg must ne nullable (either Nullable<T> or a reference type
840 if (left
.Type
.IsValueType
&& !left
.Type
.IsNullable ())
841 throw new InvalidOperationException ("Left expression can never be null");
843 if (conversion
!= null)
844 return MakeConvertedCoalesce (left
, right
, conversion
);
846 return MakeCoalesce (left
, right
);
850 // MakeBinary constructors
852 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
)
854 return MakeBinary (binaryType
, left
, right
, false, null);
857 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
)
859 return MakeBinary (binaryType
, left
, right
, liftToNull
, method
, null);
862 public static BinaryExpression
MakeBinary (ExpressionType binaryType
, Expression left
, Expression right
, bool liftToNull
, MethodInfo method
, LambdaExpression conversion
)
864 switch (binaryType
) {
865 case ExpressionType
.Add
:
866 return Add (left
, right
, method
);
867 case ExpressionType
.AddChecked
:
868 return AddChecked (left
, right
, method
);
869 case ExpressionType
.AndAlso
:
870 return AndAlso (left
, right
);
871 case ExpressionType
.Coalesce
:
872 return Coalesce (left
, right
, conversion
);
873 case ExpressionType
.Divide
:
874 return Divide (left
, right
, method
);
875 case ExpressionType
.Equal
:
876 return Equal (left
, right
, liftToNull
, method
);
877 case ExpressionType
.ExclusiveOr
:
878 return ExclusiveOr (left
, right
, method
);
879 case ExpressionType
.GreaterThan
:
880 return GreaterThan (left
, right
, liftToNull
, method
);
881 case ExpressionType
.GreaterThanOrEqual
:
882 return GreaterThanOrEqual (left
, right
, liftToNull
, method
);
883 case ExpressionType
.LeftShift
:
884 return LeftShift (left
, right
, method
);
885 case ExpressionType
.LessThan
:
886 return LessThan (left
, right
, liftToNull
, method
);
887 case ExpressionType
.LessThanOrEqual
:
888 return LessThanOrEqual (left
, right
, liftToNull
, method
);
889 case ExpressionType
.Modulo
:
890 return Modulo (left
, right
, method
);
891 case ExpressionType
.Multiply
:
892 return Multiply (left
, right
, method
);
893 case ExpressionType
.MultiplyChecked
:
894 return MultiplyChecked (left
, right
, method
);
895 case ExpressionType
.NotEqual
:
896 return NotEqual (left
, right
, liftToNull
, method
);
897 case ExpressionType
.OrElse
:
898 return OrElse (left
, right
);
899 case ExpressionType
.Power
:
900 return Power (left
, right
, method
);
901 case ExpressionType
.RightShift
:
902 return RightShift (left
, right
, method
);
903 case ExpressionType
.Subtract
:
904 return Subtract (left
, right
, method
);
905 case ExpressionType
.SubtractChecked
:
906 return SubtractChecked (left
, right
, method
);
907 case ExpressionType
.And
:
908 return And (left
, right
, method
);
909 case ExpressionType
.Or
:
910 return Or (left
, right
, method
);
913 throw new ArgumentException ("MakeBinary expect a binary node type");
918 public static MethodCallExpression
ArrayIndex (Expression array
, params Expression
[] indexes
)
920 return ArrayIndex (array
, indexes
as IEnumerable
<Expression
>);
923 public static MethodCallExpression
ArrayIndex (Expression array
, IEnumerable
<Expression
> indexes
)
928 throw new ArgumentNullException ("indexes");
930 var args
= indexes
.ToReadOnlyCollection ();
931 if (array
.Type
.GetArrayRank () != args
.Count
)
932 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
934 foreach (var arg
in args
)
935 if (arg
.Type
!= typeof (int))
936 throw new ArgumentException ("The index must be of type int");
938 return Call (array
, array
.Type
.GetMethod ("Get", PublicInstance
), args
);
941 public static UnaryExpression
ArrayLength (Expression array
)
944 throw new ArgumentNullException ("array");
945 if (!array
.Type
.IsArray
)
946 throw new ArgumentException ("The type of the expression must me Array");
947 if (array
.Type
.GetArrayRank () != 1)
948 throw new ArgumentException ("The array must be a single dimensional array");
950 return new UnaryExpression (ExpressionType
.ArrayLength
, array
, typeof (int));
953 public static MemberAssignment
Bind (MemberInfo member
, Expression expression
)
956 throw new ArgumentNullException ("member");
957 if (expression
== null)
958 throw new ArgumentNullException ("expression");
962 var prop
= member
as PropertyInfo
;
963 if (prop
!= null && prop
.GetSetMethod (true) != null)
964 type
= prop
.PropertyType
;
966 var field
= member
as FieldInfo
;
968 type
= field
.FieldType
;
971 throw new ArgumentException ("member");
973 if (!expression
.Type
.IsAssignableTo (type
))
974 throw new ArgumentException ("member");
976 return new MemberAssignment (member
, expression
);
979 public static MemberAssignment
Bind (MethodInfo propertyAccessor
, Expression expression
)
981 if (propertyAccessor
== null)
982 throw new ArgumentNullException ("propertyAccessor");
983 if (expression
== null)
984 throw new ArgumentNullException ("expression");
986 var prop
= GetAssociatedProperty (propertyAccessor
);
988 throw new ArgumentException ("propertyAccessor");
990 var setter
= prop
.GetSetMethod (true);
992 throw new ArgumentException ("setter");
994 if (!expression
.Type
.IsAssignableTo (prop
.PropertyType
))
995 throw new ArgumentException ("member");
997 return new MemberAssignment (prop
, expression
);
1000 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
)
1002 return Call (instance
, method
, null as IEnumerable
<Expression
>);
1005 public static MethodCallExpression
Call (MethodInfo method
, params Expression
[] arguments
)
1007 return Call (null, method
, arguments
as IEnumerable
<Expression
>);
1010 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
, params Expression
[] arguments
)
1012 return Call (instance
, method
, arguments
as IEnumerable
<Expression
>);
1015 public static MethodCallExpression
Call (Expression instance
, MethodInfo method
, IEnumerable
<Expression
> arguments
)
1018 throw new ArgumentNullException ("method");
1019 if (instance
== null && !method
.IsStatic
)
1020 throw new ArgumentNullException ("instance");
1021 if (method
.IsStatic
&& instance
!= null)
1022 throw new ArgumentException ("instance");
1023 if (!method
.IsStatic
&& !instance
.Type
.IsAssignableTo (method
.DeclaringType
))
1024 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
1026 var args
= CheckMethodArguments (method
, arguments
);
1028 return new MethodCallExpression (instance
, method
, args
);
1031 static Type
[] CollectTypes (IEnumerable
<Expression
> expressions
)
1033 return (from arg
in expressions
select arg
.Type
).ToArray ();
1036 static MethodInfo
TryMakeGeneric (MethodInfo method
, Type
[] args
)
1041 if (!method
.IsGenericMethod
&& args
== null)
1044 if (args
.Length
== method
.GetGenericArguments ().Length
)
1045 return method
.MakeGenericMethod (args
);
1050 public static MethodCallExpression
Call (Expression instance
, string methodName
, Type
[] typeArguments
, params Expression
[] arguments
)
1052 if (instance
== null)
1053 throw new ArgumentNullException ("instance");
1054 if (methodName
== null)
1055 throw new ArgumentNullException ("methodName");
1057 var method
= TryGetMethod (instance
.Type
, methodName
, AllInstance
,
1058 CollectTypes (arguments
), typeArguments
);
1060 var args
= CheckMethodArguments (method
, arguments
);
1062 return new MethodCallExpression (instance
, method
, args
);
1065 static bool MethodMatch (MethodInfo method
, string name
, Type
[] parameterTypes
)
1067 if (method
.Name
!= name
)
1070 var parameters
= method
.GetParameters ();
1072 if (parameters
.Length
!= parameterTypes
.Length
)
1075 if (method
.IsGenericMethod
) // if it's a generic method, when can't compare its parameters
1078 for (int i
= 0; i
< parameters
.Length
; i
++)
1079 if (!IsAssignableToParameterType (parameterTypes
[i
], parameters
[i
]))
1085 static MethodInfo
TryGetMethod (Type type
, string methodName
, BindingFlags flags
, Type
[] parameterTypes
, Type
[] argumentTypes
)
1087 var methods
= from meth
in type
.GetMethods (flags
)
1088 where
MethodMatch (meth
, methodName
, parameterTypes
)
1091 if (methods
.Count () > 1)
1092 throw new InvalidOperationException ("Too much method candidates");
1094 var method
= TryMakeGeneric (methods
.FirstOrDefault (), argumentTypes
);
1098 throw new InvalidOperationException ("No such method");
1101 public static MethodCallExpression
Call (Type type
, string methodName
, Type
[] typeArguments
, params Expression
[] arguments
)
1104 throw new ArgumentNullException ("type");
1105 if (methodName
== null)
1106 throw new ArgumentNullException ("methodName");
1108 var method
= TryGetMethod (type
, methodName
, AllStatic
,
1109 CollectTypes (arguments
), typeArguments
);
1111 var args
= CheckMethodArguments (method
, arguments
);
1113 return new MethodCallExpression (method
, args
);
1116 public static ConditionalExpression
Condition (Expression test
, Expression ifTrue
, Expression ifFalse
)
1119 throw new ArgumentNullException ("test");
1121 throw new ArgumentNullException ("ifTrue");
1122 if (ifFalse
== null)
1123 throw new ArgumentNullException ("ifFalse");
1124 if (test
.Type
!= typeof (bool))
1125 throw new ArgumentException ("Test expression should be of type bool");
1126 if (ifTrue
.Type
!= ifFalse
.Type
)
1127 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1129 return new ConditionalExpression (test
, ifTrue
, ifFalse
);
1132 public static ConstantExpression
Constant (object value)
1135 return new ConstantExpression (null, typeof (object));
1137 return Constant (value, value.GetType ());
1140 public static ConstantExpression
Constant (object value, Type type
)
1143 throw new ArgumentNullException ("type");
1146 // value must be compatible with type, no conversions
1150 if (type
.IsValueType
&& !type
.IsNullable ())
1151 throw new ArgumentException ();
1153 if (!(type
.IsValueType
&& type
.IsNullable ()) && !value.GetType ().IsAssignableTo (type
))
1154 throw new ArgumentException ();
1158 return new ConstantExpression (value, type
);
1161 static bool IsConvertiblePrimitive (Type type
)
1163 var t
= type
.GetNotNullableType ();
1165 if (t
== typeof (bool))
1171 return t
.IsPrimitive
;
1174 internal static bool IsPrimitiveConversion (Type type
, Type target
)
1179 if (type
.IsNullable () && target
== type
.GetNotNullableType ())
1182 if (target
.IsNullable () && type
== target
.GetNotNullableType ())
1185 if (IsConvertiblePrimitive (type
) && IsConvertiblePrimitive (target
))
1191 internal static bool IsReferenceConversion (Type type
, Type target
)
1196 if (type
== typeof (object) || target
== typeof (object))
1199 if (type
.IsInterface
|| target
.IsInterface
)
1202 if (type
.IsValueType
|| target
.IsValueType
)
1205 if (type
.IsAssignableTo (target
) || target
.IsAssignableTo (type
))
1211 public static UnaryExpression
Convert (Expression expression
, Type type
)
1213 return Convert (expression
, type
, null);
1216 static MethodInfo
GetUserConversionMethod (Type type
, Type target
)
1218 var method
= GetUnaryOperator ("op_Explicit", type
, type
, target
);
1220 method
= GetUnaryOperator ("op_Implicit", type
, type
, target
);
1222 method
= GetUnaryOperator ("op_Explicit", target
, type
, target
);
1224 method
= GetUnaryOperator ("op_Implicit", target
, type
, target
);
1226 throw new InvalidOperationException ();
1231 public static UnaryExpression
Convert (Expression expression
, Type type
, MethodInfo method
)
1233 if (expression
== null)
1234 throw new ArgumentNullException ("expression");
1236 throw new ArgumentNullException ("type");
1238 var et
= expression
.Type
;
1241 CheckUnaryMethod (method
, et
);
1242 else if (!IsPrimitiveConversion (et
, type
) && !IsReferenceConversion (et
, type
))
1243 method
= GetUserConversionMethod (et
, type
);
1245 return new UnaryExpression (ExpressionType
.Convert
,
1246 expression
, type
, method
,
1247 IsConvertNodeLifted (method
, expression
, type
));
1250 static bool IsConvertNodeLifted (MethodInfo method
, Expression operand
, Type target
)
1253 return operand
.Type
.IsNullable () || target
.IsNullable ();
1255 if (operand
.Type
.IsNullable () && !ParameterMatch (method
, operand
.Type
))
1258 if (target
.IsNullable () && !ReturnTypeMatch (method
, target
))
1264 static bool ParameterMatch (MethodInfo method
, Type type
)
1266 return method
.GetParameters () [0].ParameterType
== type
;
1269 static bool ReturnTypeMatch (MethodInfo method
, Type type
)
1271 return method
.ReturnType
== type
;
1274 public static UnaryExpression
ConvertChecked (Expression expression
, Type type
)
1276 return ConvertChecked (expression
, type
, null);
1279 public static UnaryExpression
ConvertChecked (Expression expression
, Type type
, MethodInfo method
)
1281 if (expression
== null)
1282 throw new ArgumentNullException ("expression");
1284 throw new ArgumentNullException ("type");
1286 var et
= expression
.Type
;
1289 CheckUnaryMethod (method
, et
);
1290 else if (IsReferenceConversion (et
, type
))
1291 return Convert (expression
, type
, method
);
1292 else if (!IsPrimitiveConversion (et
, type
))
1293 method
= GetUserConversionMethod (et
, type
);
1295 return new UnaryExpression (ExpressionType
.ConvertChecked
,
1296 expression
, type
, method
,
1297 IsConvertNodeLifted (method
, expression
, type
));
1300 public static ElementInit
ElementInit (MethodInfo addMethod
, params Expression
[] arguments
)
1302 return ElementInit (addMethod
, arguments
as IEnumerable
<Expression
>);
1305 public static ElementInit
ElementInit (MethodInfo addMethod
, IEnumerable
<Expression
> arguments
)
1307 if (addMethod
== null)
1308 throw new ArgumentNullException ("addMethod");
1309 if (arguments
== null)
1310 throw new ArgumentNullException ("arguments");
1311 if (addMethod
.Name
.ToLower (CultureInfo
.InvariantCulture
) != "add")
1312 throw new ArgumentException ("addMethod");
1313 if (addMethod
.IsStatic
)
1314 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1316 var args
= CheckMethodArguments (addMethod
, arguments
);
1318 return new ElementInit (addMethod
, args
);
1321 public static MemberExpression
Field (Expression expression
, FieldInfo field
)
1324 throw new ArgumentNullException ("field");
1325 if (!field
.IsStatic
) {
1326 if (expression
== null)
1327 throw new ArgumentNullException ("expression");
1328 if (!expression
.Type
.IsAssignableTo (field
.DeclaringType
))
1329 throw new ArgumentException ("field");
1330 } else if (expression
!= null)
1331 throw new ArgumentException ("expression");
1333 return new MemberExpression (expression
, field
, field
.FieldType
);
1336 public static MemberExpression
Field (Expression expression
, string fieldName
)
1338 if (expression
== null)
1339 throw new ArgumentNullException ("expression");
1341 var field
= expression
.Type
.GetField (fieldName
, AllInstance
);
1343 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName
, expression
.Type
));
1345 return new MemberExpression (expression
, field
, field
.FieldType
);
1348 public static Type
GetActionType (params Type
[] typeArgs
)
1350 if (typeArgs
== null)
1351 throw new ArgumentNullException ("typeArgs");
1353 if (typeArgs
.Length
> 4)
1354 throw new ArgumentException ("No Action type of this arity");
1356 if (typeArgs
.Length
== 0)
1357 return typeof (Action
);
1360 switch (typeArgs
.Length
) {
1362 action
= typeof (Action
<>);
1365 action
= typeof (Action
<,>);
1368 action
= typeof (Action
<,,>);
1371 action
= typeof (Action
<,,,>);
1375 return action
.MakeGenericType (typeArgs
);
1378 public static Type
GetFuncType (params Type
[] typeArgs
)
1380 if (typeArgs
== null)
1381 throw new ArgumentNullException ("typeArgs");
1383 if (typeArgs
.Length
< 1 || typeArgs
.Length
> 5)
1384 throw new ArgumentException ("No Func type of this arity");
1387 switch (typeArgs
.Length
) {
1389 func
= typeof (Func
<>);
1392 func
= typeof (Func
<,>);
1395 func
= typeof (Func
<,,>);
1398 func
= typeof (Func
<,,,>);
1401 func
= typeof (Func
<,,,,>);
1405 return func
.MakeGenericType (typeArgs
);
1408 public static InvocationExpression
Invoke (Expression expression
, params Expression
[] arguments
)
1410 return Invoke (expression
, arguments
as IEnumerable
<Expression
>);
1413 static Type
GetInvokableType (Type t
)
1415 if (t
.IsAssignableTo (typeof (Delegate
)))
1418 return GetGenericType (t
, typeof (Expression
<>));
1421 static Type
GetGenericType (Type t
, Type def
)
1426 if (t
.IsGenericType
&& t
.GetGenericTypeDefinition () == def
)
1429 return GetGenericType (t
.BaseType
, def
);
1432 public static InvocationExpression
Invoke (Expression expression
, IEnumerable
<Expression
> arguments
)
1434 if (expression
== null)
1435 throw new ArgumentNullException ("expression");
1437 var type
= GetInvokableType (expression
.Type
);
1439 throw new ArgumentException ("The type of the expression is not invokable");
1441 var args
= arguments
.ToReadOnlyCollection ();
1442 CheckForNull (args
, "arguments");
1444 var invoke
= type
.GetInvokeMethod ();
1446 throw new ArgumentException ("expression");
1448 if (invoke
.GetParameters ().Length
!= args
.Count
)
1449 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1451 args
= CheckMethodArguments (invoke
, args
);
1453 return new InvocationExpression (expression
, invoke
.ReturnType
, args
);
1456 static bool CanAssign (Type target
, Type source
)
1458 // This catches object and value type mixage, type compatibility is handled later
1459 if (target
.IsValueType ^ source
.IsValueType
)
1462 return source
.IsAssignableTo (target
);
1465 static Expression
CheckLambda (Type delegateType
, Expression body
, ReadOnlyCollection
<ParameterExpression
> parameters
)
1467 if (!delegateType
.IsSubclassOf (typeof (System
.Delegate
)))
1468 throw new ArgumentException ("delegateType");
1470 var invoke
= delegateType
.GetInvokeMethod ();
1472 throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
1474 var invoke_parameters
= invoke
.GetParameters ();
1475 if (invoke_parameters
.Length
!= parameters
.Count
)
1476 throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType
), "delegateType");
1478 for (int i
= 0; i
< invoke_parameters
.Length
; i
++) {
1479 if (!CanAssign (parameters
[i
].Type
, invoke_parameters
[i
].ParameterType
))
1480 throw new ArgumentException (String
.Format ("Can not assign a {0} to a {1}", invoke_parameters
[i
].ParameterType
, parameters
[i
].Type
));
1483 if (invoke
.ReturnType
!= typeof (void)) {
1484 if (!CanAssign (invoke
.ReturnType
, body
.Type
)) {
1485 if (invoke
.ReturnType
.IsExpression ())
1486 return Expression
.Quote (body
);
1488 throw new ArgumentException (String
.Format ("body type {0} can not be assigned to {1}", body
.Type
, invoke
.ReturnType
));
1494 public static Expression
<TDelegate
> Lambda
<TDelegate
> (Expression body
, params ParameterExpression
[] parameters
)
1496 return Lambda
<TDelegate
> (body
, parameters
as IEnumerable
<ParameterExpression
>);
1499 public static Expression
<TDelegate
> Lambda
<TDelegate
> (Expression body
, IEnumerable
<ParameterExpression
> parameters
)
1502 throw new ArgumentNullException ("body");
1504 var ps
= parameters
.ToReadOnlyCollection ();
1506 body
= CheckLambda (typeof (TDelegate
), body
, ps
);
1508 return new Expression
<TDelegate
> (body
, ps
);
1511 public static LambdaExpression
Lambda (Expression body
, params ParameterExpression
[] parameters
)
1514 throw new ArgumentNullException ("body");
1515 if (parameters
.Length
> 4)
1516 throw new ArgumentException ("Too many parameters");
1518 return Lambda (GetDelegateType (body
.Type
, parameters
), body
, parameters
);
1521 static Type
GetDelegateType (Type return_type
, ParameterExpression
[] parameters
)
1523 if (parameters
== null)
1524 parameters
= new ParameterExpression
[0];
1526 if (return_type
== typeof (void))
1527 return GetActionType (parameters
.Select (p
=> p
.Type
).ToArray ());
1529 var types
= new Type
[parameters
.Length
+ 1];
1530 for (int i
= 0; i
< types
.Length
- 1; i
++)
1531 types
[i
] = parameters
[i
].Type
;
1533 types
[types
.Length
- 1] = return_type
;
1534 return GetFuncType (types
);
1537 public static LambdaExpression
Lambda (Type delegateType
, Expression body
, params ParameterExpression
[] parameters
)
1539 return Lambda (delegateType
, body
, parameters
as IEnumerable
<ParameterExpression
>);
1542 static LambdaExpression
CreateExpressionOf (Type type
, Expression body
, ReadOnlyCollection
<ParameterExpression
> parameters
)
1544 return (LambdaExpression
) typeof (Expression
<>).MakeGenericType (type
).GetConstructor (
1545 NonPublicInstance
, null, new [] { typeof (Expression), typeof (ReadOnlyCollection<ParameterExpression>) }
, null).Invoke (new object [] { body, parameters }
);
1548 public static LambdaExpression
Lambda (Type delegateType
, Expression body
, IEnumerable
<ParameterExpression
> parameters
)
1550 if (delegateType
== null)
1551 throw new ArgumentNullException ("delegateType");
1553 throw new ArgumentNullException ("body");
1555 var ps
= parameters
.ToReadOnlyCollection ();
1557 body
= CheckLambda (delegateType
, body
, ps
);
1559 return CreateExpressionOf (delegateType
, body
, ps
);
1562 public static MemberListBinding
ListBind (MemberInfo member
, params ElementInit
[] initializers
)
1564 return ListBind (member
, initializers
as IEnumerable
<ElementInit
>);
1567 static void CheckIsAssignableToIEnumerable (Type t
)
1569 if (!t
.IsAssignableTo (typeof (IEnumerable
)))
1570 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t
));
1573 public static MemberListBinding
ListBind (MemberInfo member
, IEnumerable
<ElementInit
> initializers
)
1576 throw new ArgumentNullException ("member");
1577 if (initializers
== null)
1578 throw new ArgumentNullException ("initializers");
1580 var inits
= initializers
.ToReadOnlyCollection ();
1581 CheckForNull (inits
, "initializers");
1583 member
.OnFieldOrProperty (
1584 field
=> CheckIsAssignableToIEnumerable (field
.FieldType
),
1585 prop
=> CheckIsAssignableToIEnumerable (prop
.PropertyType
));
1587 return new MemberListBinding (member
, inits
);
1590 public static MemberListBinding
ListBind (MethodInfo propertyAccessor
, params ElementInit
[] initializers
)
1592 return ListBind (propertyAccessor
, initializers
as IEnumerable
<ElementInit
>);
1595 static void CheckForNull
<T
> (ReadOnlyCollection
<T
> collection
, string name
) where T
: class
1597 foreach (var t
in collection
)
1599 throw new ArgumentNullException (name
);
1602 public static MemberListBinding
ListBind (MethodInfo propertyAccessor
, IEnumerable
<ElementInit
> initializers
)
1604 if (propertyAccessor
== null)
1605 throw new ArgumentNullException ("propertyAccessor");
1606 if (initializers
== null)
1607 throw new ArgumentNullException ("initializers");
1609 var inits
= initializers
.ToReadOnlyCollection ();
1610 CheckForNull (inits
, "initializers");
1612 var prop
= GetAssociatedProperty (propertyAccessor
);
1614 throw new ArgumentException ("propertyAccessor");
1616 CheckIsAssignableToIEnumerable (prop
.PropertyType
);
1618 return new MemberListBinding (prop
, inits
);
1621 public static ListInitExpression
ListInit (NewExpression newExpression
, params ElementInit
[] initializers
)
1623 return ListInit (newExpression
, initializers
as IEnumerable
<ElementInit
>);
1626 public static ListInitExpression
ListInit (NewExpression newExpression
, IEnumerable
<ElementInit
> initializers
)
1628 var inits
= CheckListInit (newExpression
, initializers
);
1630 return new ListInitExpression (newExpression
, inits
);
1633 public static ListInitExpression
ListInit (NewExpression newExpression
, params Expression
[] initializers
)
1635 return ListInit (newExpression
, initializers
as IEnumerable
<Expression
>);
1638 public static ListInitExpression
ListInit (NewExpression newExpression
, IEnumerable
<Expression
> initializers
)
1640 var inits
= CheckListInit (newExpression
, initializers
);
1642 var add_method
= GetAddMethod (newExpression
.Type
, inits
[0].Type
);
1643 if (add_method
== null)
1644 throw new InvalidOperationException ("No suitable add method found");
1646 return new ListInitExpression (newExpression
, CreateInitializers (add_method
, inits
));
1649 static ReadOnlyCollection
<ElementInit
> CreateInitializers (MethodInfo add_method
, ReadOnlyCollection
<Expression
> initializers
)
1651 return (from init
in initializers
select Expression
.ElementInit (add_method
, init
)).ToReadOnlyCollection ();
1654 static MethodInfo
GetAddMethod (Type type
, Type arg
)
1656 return type
.GetMethod ("Add", PublicInstance
| BindingFlags
.IgnoreCase
, null, new [] { arg }
, null);
1659 public static ListInitExpression
ListInit (NewExpression newExpression
, MethodInfo addMethod
, params Expression
[] initializers
)
1661 return ListInit (newExpression
, addMethod
, initializers
as IEnumerable
<Expression
>);
1664 static ReadOnlyCollection
<T
> CheckListInit
<T
> (NewExpression newExpression
, IEnumerable
<T
> initializers
) where T
: class
1666 if (newExpression
== null)
1667 throw new ArgumentNullException ("newExpression");
1668 if (initializers
== null)
1669 throw new ArgumentNullException ("initializers");
1670 if (!newExpression
.Type
.IsAssignableTo (typeof (IEnumerable
)))
1671 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1673 var inits
= initializers
.ToReadOnlyCollection ();
1674 if (inits
.Count
== 0)
1675 throw new ArgumentException ("Empty initializers");
1677 CheckForNull (inits
, "initializers");
1682 public static ListInitExpression
ListInit (NewExpression newExpression
, MethodInfo addMethod
, IEnumerable
<Expression
> initializers
)
1684 var inits
= CheckListInit (newExpression
, initializers
);
1686 if (addMethod
!= null) {
1687 if (addMethod
.Name
.ToLower (CultureInfo
.InvariantCulture
) != "add")
1688 throw new ArgumentException ("addMethod");
1690 var parameters
= addMethod
.GetParameters ();
1691 if (parameters
.Length
!= 1)
1692 throw new ArgumentException ("addMethod");
1694 foreach (var expression
in inits
)
1695 if (!IsAssignableToParameterType (expression
.Type
, parameters
[0]))
1696 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1699 if (addMethod
== null)
1700 addMethod
= GetAddMethod (newExpression
.Type
, inits
[0].Type
);
1702 if (addMethod
== null)
1703 throw new InvalidOperationException ("No suitable add method found");
1705 return new ListInitExpression (newExpression
, CreateInitializers (addMethod
, inits
));
1708 public static MemberExpression
MakeMemberAccess (Expression expression
, MemberInfo member
)
1710 if (expression
== null)
1711 throw new ArgumentNullException ("expression");
1713 throw new ArgumentNullException ("member");
1715 var field
= member
as FieldInfo
;
1717 return Field (expression
, field
);
1719 var property
= member
as PropertyInfo
;
1720 if (property
!= null)
1721 return Property (expression
, property
);
1723 throw new ArgumentException ("Member should either be a field or a property");
1726 public static UnaryExpression
MakeUnary (ExpressionType unaryType
, Expression operand
, Type type
)
1728 return MakeUnary (unaryType
, operand
, type
, null);
1731 public static UnaryExpression
MakeUnary (ExpressionType unaryType
, Expression operand
, Type type
, MethodInfo method
)
1733 switch (unaryType
) {
1734 case ExpressionType
.ArrayLength
:
1735 return ArrayLength (operand
);
1736 case ExpressionType
.Convert
:
1737 return Convert (operand
, type
, method
);
1738 case ExpressionType
.ConvertChecked
:
1739 return ConvertChecked (operand
, type
, method
);
1740 case ExpressionType
.Negate
:
1741 return Negate (operand
, method
);
1742 case ExpressionType
.NegateChecked
:
1743 return NegateChecked (operand
, method
);
1744 case ExpressionType
.Not
:
1745 return Not (operand
, method
);
1746 case ExpressionType
.Quote
:
1747 return Quote (operand
);
1748 case ExpressionType
.TypeAs
:
1749 return TypeAs (operand
, type
);
1750 case ExpressionType
.UnaryPlus
:
1751 return UnaryPlus (operand
, method
);
1754 throw new ArgumentException ("MakeUnary expect an unary operator");
1757 public static MemberMemberBinding
MemberBind (MemberInfo member
, params MemberBinding
[] bindings
)
1759 return MemberBind (member
, bindings
as IEnumerable
<MemberBinding
>);
1762 public static MemberMemberBinding
MemberBind (MemberInfo member
, IEnumerable
<MemberBinding
> bindings
)
1765 throw new ArgumentNullException ("member");
1767 var type
= member
.OnFieldOrProperty (
1768 field
=> field
.FieldType
,
1769 prop
=> prop
.PropertyType
);
1771 return new MemberMemberBinding (member
, CheckMemberBindings (type
, bindings
));
1774 public static MemberMemberBinding
MemberBind (MethodInfo propertyAccessor
, params MemberBinding
[] bindings
)
1776 return MemberBind (propertyAccessor
, bindings
as IEnumerable
<MemberBinding
>);
1779 public static MemberMemberBinding
MemberBind (MethodInfo propertyAccessor
, IEnumerable
<MemberBinding
> bindings
)
1781 if (propertyAccessor
== null)
1782 throw new ArgumentNullException ("propertyAccessor");
1784 var bds
= bindings
.ToReadOnlyCollection ();
1785 CheckForNull (bds
, "bindings");
1787 var prop
= GetAssociatedProperty (propertyAccessor
);
1789 throw new ArgumentException ("propertyAccessor");
1791 return new MemberMemberBinding (prop
, CheckMemberBindings (prop
.PropertyType
, bindings
));
1794 static ReadOnlyCollection
<MemberBinding
> CheckMemberBindings (Type type
, IEnumerable
<MemberBinding
> bindings
)
1796 if (bindings
== null)
1797 throw new ArgumentNullException ("bindings");
1799 var bds
= bindings
.ToReadOnlyCollection ();
1800 CheckForNull (bds
, "bindings");
1802 foreach (var binding
in bds
)
1803 if (!type
.IsAssignableTo (binding
.Member
.DeclaringType
))
1804 throw new ArgumentException ("Type not assignable to member type");
1809 public static MemberInitExpression
MemberInit (NewExpression newExpression
, params MemberBinding
[] bindings
)
1811 return MemberInit (newExpression
, bindings
as IEnumerable
<MemberBinding
>);
1814 public static MemberInitExpression
MemberInit (NewExpression newExpression
, IEnumerable
<MemberBinding
> bindings
)
1816 if (newExpression
== null)
1817 throw new ArgumentNullException ("newExpression");
1819 return new MemberInitExpression (newExpression
, CheckMemberBindings (newExpression
.Type
, bindings
));
1822 public static UnaryExpression
Negate (Expression expression
)
1824 return Negate (expression
, null);
1827 public static UnaryExpression
Negate (Expression expression
, MethodInfo method
)
1829 method
= UnaryCoreCheck ("op_UnaryNegation", expression
, method
, type
=> IsSignedNumber (type
));
1831 return MakeSimpleUnary (ExpressionType
.Negate
, expression
, method
);
1834 public static UnaryExpression
NegateChecked (Expression expression
)
1836 return NegateChecked (expression
, null);
1839 public static UnaryExpression
NegateChecked (Expression expression
, MethodInfo method
)
1841 method
= UnaryCoreCheck ("op_UnaryNegation", expression
, method
, type
=> IsSignedNumber (type
));
1843 return MakeSimpleUnary (ExpressionType
.NegateChecked
, expression
, method
);
1846 public static NewExpression
New (ConstructorInfo constructor
)
1848 if (constructor
== null)
1849 throw new ArgumentNullException ("constructor");
1851 if (constructor
.GetParameters ().Length
> 0)
1852 throw new ArgumentException ("Constructor must be parameter less");
1854 return new NewExpression (constructor
, (null as IEnumerable
<Expression
>).ToReadOnlyCollection (), null);
1857 public static NewExpression
New (Type type
)
1860 throw new ArgumentNullException ("type");
1862 CheckNotVoid (type
);
1864 var args
= (null as IEnumerable
<Expression
>).ToReadOnlyCollection ();
1866 if (type
.IsValueType
)
1867 return new NewExpression (type
, args
);
1869 var ctor
= type
.GetConstructor (Type
.EmptyTypes
);
1871 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1873 return new NewExpression (ctor
, args
, null);
1876 public static NewExpression
New (ConstructorInfo constructor
, params Expression
[] arguments
)
1878 return New (constructor
, arguments
as IEnumerable
<Expression
>);
1881 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
)
1883 if (constructor
== null)
1884 throw new ArgumentNullException ("constructor");
1886 var args
= CheckMethodArguments (constructor
, arguments
);
1888 return new NewExpression (constructor
, args
, null);
1891 static IList
<Expression
> CreateArgumentList (IEnumerable
<Expression
> arguments
)
1893 if (arguments
== null)
1894 return arguments
.ToReadOnlyCollection ();
1896 return arguments
.ToList ();
1899 static ReadOnlyCollection
<Expression
> CheckMethodArguments (MethodBase method
, IEnumerable
<Expression
> args
)
1901 var arguments
= CreateArgumentList (args
);
1902 var parameters
= method
.GetParameters ();
1904 if (arguments
.Count
!= parameters
.Length
)
1905 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1907 for (int i
= 0; i
< parameters
.Length
; i
++) {
1908 if (arguments
[i
] == null)
1909 throw new ArgumentNullException ("arguments");
1911 if (!IsAssignableToParameterType (arguments
[i
].Type
, parameters
[i
])) {
1912 if (!parameters
[i
].ParameterType
.IsExpression ())
1913 throw new ArgumentException ("arguments");
1915 arguments
[i
] = Expression
.Quote (arguments
[i
]);
1919 return arguments
.ToReadOnlyCollection ();
1922 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
, params MemberInfo
[] members
)
1924 return New (constructor
, arguments
, members
as IEnumerable
<MemberInfo
>);
1927 public static NewExpression
New (ConstructorInfo constructor
, IEnumerable
<Expression
> arguments
, IEnumerable
<MemberInfo
> members
)
1929 if (constructor
== null)
1930 throw new ArgumentNullException ("constructor");
1932 var args
= arguments
.ToReadOnlyCollection ();
1933 var mmbs
= members
.ToReadOnlyCollection ();
1935 CheckForNull (args
, "arguments");
1936 CheckForNull (mmbs
, "members");
1938 args
= CheckMethodArguments (constructor
, arguments
);
1940 if (args
.Count
!= mmbs
.Count
)
1941 throw new ArgumentException ("Arguments count does not match members count");
1943 for (int i
= 0; i
< mmbs
.Count
; i
++) {
1944 var member
= mmbs
[i
];
1946 switch (member
.MemberType
) {
1947 case MemberTypes
.Field
:
1948 type
= (member
as FieldInfo
).FieldType
;
1950 case MemberTypes
.Method
:
1951 type
= (member
as MethodInfo
).ReturnType
;
1953 case MemberTypes
.Property
:
1954 var prop
= member
as PropertyInfo
;
1955 if (prop
.GetGetMethod (true) == null)
1956 throw new ArgumentException ("Property must have a getter");
1958 type
= (member
as PropertyInfo
).PropertyType
;
1961 throw new ArgumentException ("Member type not allowed");
1964 if (!args
[i
].Type
.IsAssignableTo (type
))
1965 throw new ArgumentException ("Argument type not assignable to member type");
1968 return new NewExpression (constructor
, args
, mmbs
);
1971 public static NewArrayExpression
NewArrayBounds (Type type
, params Expression
[] bounds
)
1973 return NewArrayBounds (type
, bounds
as IEnumerable
<Expression
>);
1976 public static NewArrayExpression
NewArrayBounds (Type type
, IEnumerable
<Expression
> bounds
)
1979 throw new ArgumentNullException ("type");
1981 throw new ArgumentNullException ("bounds");
1983 CheckNotVoid (type
);
1985 var array_bounds
= bounds
.ToReadOnlyCollection ();
1986 foreach (var expression
in array_bounds
)
1987 if (!IsInt (expression
.Type
))
1988 throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1990 return new NewArrayExpression (ExpressionType
.NewArrayBounds
, type
.MakeArrayType (array_bounds
.Count
), array_bounds
);
1993 public static NewArrayExpression
NewArrayInit (Type type
, params Expression
[] initializers
)
1995 return NewArrayInit (type
, initializers
as IEnumerable
<Expression
>);
1998 public static NewArrayExpression
NewArrayInit (Type type
, IEnumerable
<Expression
> initializers
)
2001 throw new ArgumentNullException ("type");
2002 if (initializers
== null)
2003 throw new ArgumentNullException ("initializers");
2005 CheckNotVoid (type
);
2007 var inits
= initializers
.ToReadOnlyCollection ();
2009 foreach (var expression
in inits
) {
2010 if (expression
== null)
2011 throw new ArgumentNullException ("initializers");
2013 if (!expression
.Type
.IsAssignableTo (type
))
2014 throw new InvalidOperationException (
2015 string.Format ("{0} IsAssignableTo {1}, expression [ {2} ] : {3}", expression
.Type
, type
, expression
.NodeType
, expression
));
2017 // TODO: Quote elements if type == typeof (Expression)
2020 return new NewArrayExpression (ExpressionType
.NewArrayInit
, type
.MakeArrayType (), inits
);
2023 public static UnaryExpression
Not (Expression expression
)
2025 return Not (expression
, null);
2028 public static UnaryExpression
Not (Expression expression
, MethodInfo method
)
2030 Func
<Type
, bool> validator
= type
=> IsIntOrBool (type
);
2032 method
= UnaryCoreCheck ("op_LogicalNot", expression
, method
, validator
);
2035 method
= UnaryCoreCheck ("op_OnesComplement", expression
, method
, validator
);
2037 return MakeSimpleUnary (ExpressionType
.Not
, expression
, method
);
2040 static void CheckNotVoid (Type type
)
2042 if (type
== typeof (void))
2043 throw new ArgumentException ("Type can't be void");
2046 public static ParameterExpression
Parameter (Type type
, string name
)
2049 throw new ArgumentNullException ("type");
2051 CheckNotVoid (type
);
2053 return new ParameterExpression (type
, name
);
2056 public static MemberExpression
Property (Expression expression
, MethodInfo propertyAccessor
)
2058 if (propertyAccessor
== null)
2059 throw new ArgumentNullException ("propertyAccessor");
2061 if (!propertyAccessor
.IsStatic
) {
2062 if (expression
== null)
2063 throw new ArgumentNullException ("expression");
2064 if (!expression
.Type
.IsAssignableTo (propertyAccessor
.DeclaringType
))
2065 throw new ArgumentException ("expression");
2066 } else if (expression
!= null)
2067 throw new ArgumentException ("expression");
2069 var prop
= GetAssociatedProperty (propertyAccessor
);
2071 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor
));
2073 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2076 static PropertyInfo
GetAssociatedProperty (MethodInfo method
)
2081 foreach (var prop
in method
.DeclaringType
.GetProperties (All
)) {
2082 if (method
.Equals (prop
.GetGetMethod (true)))
2084 if (method
.Equals (prop
.GetSetMethod (true)))
2091 public static MemberExpression
Property (Expression expression
, PropertyInfo property
)
2093 if (property
== null)
2094 throw new ArgumentNullException ("property");
2096 var getter
= property
.GetGetMethod (true);
2098 throw new ArgumentException ("getter");
2100 if (!getter
.IsStatic
) {
2101 if (expression
== null)
2102 throw new ArgumentNullException ("expression");
2103 if (!expression
.Type
.IsAssignableTo (property
.DeclaringType
))
2104 throw new ArgumentException ("expression");
2105 } else if (expression
!= null)
2106 throw new ArgumentException ("expression");
2108 return new MemberExpression (expression
, property
, property
.PropertyType
);
2111 public static MemberExpression
Property (Expression expression
, string propertyName
)
2113 if (expression
== null)
2114 throw new ArgumentNullException ("expression");
2116 var prop
= expression
.Type
.GetProperty (propertyName
, AllInstance
);
2118 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName
, expression
.Type
));
2120 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2123 public static MemberExpression
PropertyOrField (Expression expression
, string propertyOrFieldName
)
2125 if (expression
== null)
2126 throw new ArgumentNullException ("expression");
2127 if (propertyOrFieldName
== null)
2128 throw new ArgumentNullException ("propertyOrFieldName");
2130 var prop
= expression
.Type
.GetProperty (propertyOrFieldName
, AllInstance
);
2132 return new MemberExpression (expression
, prop
, prop
.PropertyType
);
2134 var field
= expression
.Type
.GetField (propertyOrFieldName
, AllInstance
);
2136 return new MemberExpression (expression
, field
, field
.FieldType
);
2138 throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName
, expression
.Type
));
2141 public static UnaryExpression
Quote (Expression expression
)
2143 if (expression
== null)
2144 throw new ArgumentNullException ("expression");
2146 return new UnaryExpression (ExpressionType
.Quote
, expression
, expression
.GetType ());
2149 public static UnaryExpression
TypeAs (Expression expression
, Type type
)
2151 if (expression
== null)
2152 throw new ArgumentNullException ("expression");
2154 throw new ArgumentNullException ("type");
2155 if (type
.IsValueType
&& !type
.IsNullable ())
2156 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
2158 return new UnaryExpression (ExpressionType
.TypeAs
, expression
, type
);
2161 public static TypeBinaryExpression
TypeIs (Expression expression
, Type type
)
2163 if (expression
== null)
2164 throw new ArgumentNullException ("expression");
2166 throw new ArgumentNullException ("type");
2168 CheckNotVoid (type
);
2170 return new TypeBinaryExpression (ExpressionType
.TypeIs
, expression
, type
, typeof (bool));
2173 public static UnaryExpression
UnaryPlus (Expression expression
)
2175 return UnaryPlus (expression
, null);
2178 public static UnaryExpression
UnaryPlus (Expression expression
, MethodInfo method
)
2180 method
= UnaryCoreCheck ("op_UnaryPlus", expression
, method
, type
=> IsNumber (type
));
2182 return MakeSimpleUnary (ExpressionType
.UnaryPlus
, expression
, method
);
2185 static bool IsInt (Type t
)
2187 return t
== typeof (byte) || t
== typeof (sbyte) ||
2188 t
== typeof (short) || t
== typeof (ushort) ||
2189 t
== typeof (int) || t
== typeof (uint) ||
2190 t
== typeof (long) || t
== typeof (ulong);
2193 static bool IsIntOrBool (Type t
)
2195 return IsInt (t
) || t
== typeof (bool);
2198 static bool IsNumber (Type t
)
2203 return t
== typeof (float) || t
== typeof (double) || t
== typeof (decimal);
2206 static bool IsSignedNumber (Type t
)
2208 return IsNumber (t
) && !IsUnsigned (t
);
2211 internal static bool IsUnsigned (Type t
)
2215 return IsUnsigned (t
.GetElementType ());
2218 return t
== typeof (ushort) ||
2219 t
== typeof (uint) ||
2220 t
== typeof (ulong) ||
2225 // This method must be overwritten by derived classes to
2226 // compile the expression
2228 internal virtual void Emit (EmitContext ec
)
2230 throw new NotImplementedException ();