1 2 /* **************************************************************************** 3 * 4 * Copyright (c) Microsoft Corporation. 5 * 6 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 7 * copy of the license can be found in the License.html file at the root of this distribution. If 8 * you cannot locate the Apache License, Version 2.0, please send an email to 9 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 10 * by the terms of the Apache License, Version 2.0. 11 * 12 * You must not remove this notice, or any other, from this software. 13 * 14 * 15 * ***************************************************************************/ 16 17 using System; 18 using System.Collections.Generic; 19 using System.Diagnostics; 20 using System.Dynamic.Utils; 21 using System.Reflection; 22 23 #if SILVERLIGHT 24 using System.Core; 25 #endif 26 27 #if CLR2 28 namespace Microsoft.Scripting.Ast { 29 #else 30 namespace System.Linq.Expressions { 31 #endif 32 33 /// <summary> 34 /// Represents an expression that has a binary operator. 35 /// </summary> 36 #if !SILVERLIGHT 37 [DebuggerTypeProxy(typeof(Expression.BinaryExpressionProxy))] 38 #endif 39 public class BinaryExpression : Expression { 40 private readonly Expression _left; 41 private readonly Expression _right; 42 BinaryExpression(Expression left, Expression right)43 internal BinaryExpression(Expression left, Expression right) { 44 _left = left; 45 _right = right; 46 } 47 48 /// <summary> 49 /// Gets a value that indicates whether the expression tree node can be reduced. 50 /// </summary> 51 public override bool CanReduce { 52 get { 53 // Only OpAssignments are reducible. 54 return IsOpAssignment(NodeType); 55 } 56 } 57 IsOpAssignment(ExpressionType op)58 private static bool IsOpAssignment(ExpressionType op) { 59 switch (op) { 60 case ExpressionType.AddAssign: 61 case ExpressionType.SubtractAssign: 62 case ExpressionType.MultiplyAssign: 63 case ExpressionType.AddAssignChecked: 64 case ExpressionType.SubtractAssignChecked: 65 case ExpressionType.MultiplyAssignChecked: 66 case ExpressionType.DivideAssign: 67 case ExpressionType.ModuloAssign: 68 case ExpressionType.PowerAssign: 69 case ExpressionType.AndAssign: 70 case ExpressionType.OrAssign: 71 case ExpressionType.RightShiftAssign: 72 case ExpressionType.LeftShiftAssign: 73 case ExpressionType.ExclusiveOrAssign: 74 return true; 75 } 76 return false; 77 } 78 79 /// <summary> 80 /// Gets the right operand of the binary operation. 81 /// </summary> 82 public Expression Right { 83 get { return _right; } 84 } 85 86 /// <summary> 87 /// Gets the left operand of the binary operation. 88 /// </summary> 89 public Expression Left { 90 get { return _left; } 91 } 92 93 /// <summary> 94 /// Gets the implementing method for the binary operation. 95 /// </summary> 96 public MethodInfo Method { 97 get { return GetMethod(); } 98 } 99 GetMethod()100 internal virtual MethodInfo GetMethod() { 101 return null; 102 } 103 104 // Note: takes children in evaluation order, which is also the order 105 // that ExpressionVisitor visits them. Having them this way reduces the 106 // chances people will make a mistake and use an inconsistent order in 107 // derived visitors. 108 109 /// <summary> 110 /// Creates a new expression that is like this one, but using the 111 /// supplied children. If all of the children are the same, it will 112 /// return this expression. 113 /// </summary> 114 /// <param name="left">The <see cref="Left" /> property of the result.</param> 115 /// <param name="conversion">The <see cref="Conversion" /> property of the result.</param> 116 /// <param name="right">The <see cref="Right" /> property of the result.</param> 117 /// <returns>This expression if no children changed, or an expression with the updated children.</returns> Update(Expression left, LambdaExpression conversion, Expression right)118 public BinaryExpression Update(Expression left, LambdaExpression conversion, Expression right) { 119 if (left == Left && right == Right && conversion == Conversion) { 120 return this; 121 } 122 if (IsReferenceComparison) { 123 if (NodeType == ExpressionType.Equal) { 124 return Expression.ReferenceEqual(left, right); 125 } else { 126 return Expression.ReferenceNotEqual(left, right); 127 } 128 } 129 return Expression.MakeBinary(NodeType, left, right, IsLiftedToNull, Method, conversion); 130 } 131 132 /// <summary> 133 /// Reduces the binary expression node to a simpler expression. 134 /// If CanReduce returns true, this should return a valid expression. 135 /// This method is allowed to return another node which itself 136 /// must be reduced. 137 /// </summary> 138 /// <returns>The reduced expression.</returns> Reduce()139 public override Expression Reduce() { 140 // Only reduce OpAssignment expressions. 141 if (IsOpAssignment(NodeType)) { 142 switch (_left.NodeType) { 143 case ExpressionType.MemberAccess: 144 return ReduceMember(); 145 146 case ExpressionType.Index: 147 return ReduceIndex(); 148 149 default: 150 return ReduceVariable(); 151 } 152 } 153 return this; 154 } 155 156 // Return the corresponding Op of an assignment op. GetBinaryOpFromAssignmentOp(ExpressionType op)157 private static ExpressionType GetBinaryOpFromAssignmentOp(ExpressionType op) { 158 Debug.Assert(IsOpAssignment(op)); 159 switch (op) { 160 case ExpressionType.AddAssign: 161 return ExpressionType.Add; 162 case ExpressionType.AddAssignChecked: 163 return ExpressionType.AddChecked; 164 case ExpressionType.SubtractAssign: 165 return ExpressionType.Subtract; 166 case ExpressionType.SubtractAssignChecked: 167 return ExpressionType.SubtractChecked; 168 case ExpressionType.MultiplyAssign: 169 return ExpressionType.Multiply; 170 case ExpressionType.MultiplyAssignChecked: 171 return ExpressionType.MultiplyChecked; 172 case ExpressionType.DivideAssign: 173 return ExpressionType.Divide; 174 case ExpressionType.ModuloAssign: 175 return ExpressionType.Modulo; 176 case ExpressionType.PowerAssign: 177 return ExpressionType.Power; 178 case ExpressionType.AndAssign: 179 return ExpressionType.And; 180 case ExpressionType.OrAssign: 181 return ExpressionType.Or; 182 case ExpressionType.RightShiftAssign: 183 return ExpressionType.RightShift; 184 case ExpressionType.LeftShiftAssign: 185 return ExpressionType.LeftShift; 186 case ExpressionType.ExclusiveOrAssign: 187 return ExpressionType.ExclusiveOr; 188 default: 189 // must be an error 190 throw Error.InvalidOperation("op"); 191 } 192 193 } 194 ReduceVariable()195 private Expression ReduceVariable() { 196 // v (op)= r 197 // ... is reduced into ... 198 // v = v (op) r 199 ExpressionType op = GetBinaryOpFromAssignmentOp(NodeType); 200 Expression r = Expression.MakeBinary(op, _left, _right, false, Method); 201 LambdaExpression conversion = GetConversion(); 202 if (conversion != null) { 203 r = Expression.Invoke(conversion, r); 204 } 205 return Expression.Assign(_left, r); 206 } 207 ReduceMember()208 private Expression ReduceMember() { 209 MemberExpression member = (MemberExpression)_left; 210 211 if (member.Expression == null) { 212 // static member, reduce the same as variable 213 return ReduceVariable(); 214 } else { 215 // left.b (op)= r 216 // ... is reduced into ... 217 // temp1 = left 218 // temp2 = temp1.b (op) r 219 // temp1.b = temp2 220 // temp2 221 ParameterExpression temp1 = Variable(member.Expression.Type, "temp1"); 222 223 // 1. temp1 = left 224 Expression e1 = Expression.Assign(temp1, member.Expression); 225 226 // 2. temp2 = temp1.b (op) r 227 ExpressionType op = GetBinaryOpFromAssignmentOp(NodeType); 228 Expression e2 = Expression.MakeBinary(op, Expression.MakeMemberAccess(temp1, member.Member), _right, false, Method); 229 LambdaExpression conversion = GetConversion(); 230 if (conversion != null) { 231 e2 = Expression.Invoke(conversion, e2); 232 } 233 ParameterExpression temp2 = Variable(e2.Type, "temp2"); 234 e2 = Expression.Assign(temp2, e2); 235 236 // 3. temp1.b = temp2 237 Expression e3 = Expression.Assign(Expression.MakeMemberAccess(temp1, member.Member), temp2); 238 239 // 3. temp2 240 Expression e4 = temp2; 241 242 return Expression.Block( 243 new ParameterExpression[] { temp1, temp2 }, 244 e1, e2, e3, e4 245 ); 246 } 247 } 248 ReduceIndex()249 private Expression ReduceIndex() { 250 // left[a0, a1, ... aN] (op)= r 251 // 252 // ... is reduced into ... 253 // 254 // tempObj = left 255 // tempArg0 = a0 256 // ... 257 // tempArgN = aN 258 // tempValue = tempObj[tempArg0, ... tempArgN] (op) r 259 // tempObj[tempArg0, ... tempArgN] = tempValue 260 261 var index = (IndexExpression)_left; 262 263 var vars = new List<ParameterExpression>(index.Arguments.Count + 2); 264 var exprs = new List<Expression>(index.Arguments.Count + 3); 265 266 var tempObj = Expression.Variable(index.Object.Type, "tempObj"); 267 vars.Add(tempObj); 268 exprs.Add(Expression.Assign(tempObj, index.Object)); 269 270 var tempArgs = new List<Expression>(index.Arguments.Count); 271 foreach (var arg in index.Arguments) { 272 var tempArg = Expression.Variable(arg.Type, "tempArg" + tempArgs.Count); 273 vars.Add(tempArg); 274 tempArgs.Add(tempArg); 275 exprs.Add(Expression.Assign(tempArg, arg)); 276 } 277 278 var tempIndex = Expression.MakeIndex(tempObj, index.Indexer, tempArgs); 279 280 // tempValue = tempObj[tempArg0, ... tempArgN] (op) r 281 ExpressionType binaryOp = GetBinaryOpFromAssignmentOp(NodeType); 282 Expression op = Expression.MakeBinary(binaryOp, tempIndex, _right, false, Method); 283 LambdaExpression conversion = GetConversion(); 284 if (conversion != null) { 285 op = Expression.Invoke(conversion, op); 286 } 287 var tempValue = Expression.Variable(op.Type, "tempValue"); 288 vars.Add(tempValue); 289 exprs.Add(Expression.Assign(tempValue, op)); 290 291 // tempObj[tempArg0, ... tempArgN] = tempValue 292 exprs.Add(Expression.Assign(tempIndex, tempValue)); 293 294 return Expression.Block(vars, exprs); 295 } 296 297 /// <summary> 298 /// Gets the type conversion function that is used by a coalescing or compound assignment operation. 299 /// </summary> 300 public LambdaExpression Conversion { 301 get { return GetConversion(); } 302 } 303 GetConversion()304 internal virtual LambdaExpression GetConversion() { 305 return null; 306 } 307 308 /// <summary> 309 /// Gets a value that indicates whether the expression tree node represents a lifted call to an operator. 310 /// </summary> 311 public bool IsLifted { 312 get { 313 if (NodeType == ExpressionType.Coalesce || NodeType == ExpressionType.Assign) { 314 return false; 315 } 316 if (TypeUtils.IsNullableType(_left.Type)) { 317 MethodInfo method = GetMethod(); 318 return method == null || 319 !TypeUtils.AreEquivalent(method.GetParametersCached()[0].ParameterType.GetNonRefType(), _left.Type); 320 } 321 return false; 322 } 323 } 324 /// <summary> 325 /// Gets a value that indicates whether the expression tree node represents a lifted call to an operator whose return type is lifted to a nullable type. 326 /// </summary> 327 public bool IsLiftedToNull { 328 get { 329 return IsLifted && TypeUtils.IsNullableType(Type); 330 } 331 } 332 333 /// <summary> 334 /// Dispatches to the specific visit method for this node type. 335 /// </summary> Accept(ExpressionVisitor visitor)336 protected internal override Expression Accept(ExpressionVisitor visitor) { 337 return visitor.VisitBinary(this); 338 } 339 Create(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion)340 internal static Expression Create(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion) { 341 if (nodeType == ExpressionType.Assign) { 342 Debug.Assert(method == null && TypeUtils.AreEquivalent(type, left.Type)); 343 return new AssignBinaryExpression(left, right); 344 } 345 if (conversion != null) { 346 Debug.Assert(method == null && TypeUtils.AreEquivalent(type, right.Type) && nodeType == ExpressionType.Coalesce); 347 return new CoalesceConversionBinaryExpression(left, right, conversion); 348 } 349 if (method != null) { 350 return new MethodBinaryExpression(nodeType, left, right, type, method); 351 } 352 if (type == typeof(bool)) { 353 return new LogicalBinaryExpression(nodeType, left, right); 354 } 355 return new SimpleBinaryExpression(nodeType, left, right, type); 356 } 357 358 internal bool IsLiftedLogical { 359 get { 360 Type left = _left.Type; 361 Type right = _right.Type; 362 MethodInfo method = GetMethod(); 363 ExpressionType kind = NodeType; 364 365 return 366 (kind == ExpressionType.AndAlso || kind == ExpressionType.OrElse) && 367 TypeUtils.AreEquivalent(right, left) && 368 TypeUtils.IsNullableType(left) && 369 method != null && 370 TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left)); 371 } 372 } 373 374 internal bool IsReferenceComparison { 375 get { 376 Type left = _left.Type; 377 Type right = _right.Type; 378 MethodInfo method = GetMethod(); 379 ExpressionType kind = NodeType; 380 381 return (kind == ExpressionType.Equal || kind == ExpressionType.NotEqual) && 382 method == null && !left.IsValueType && !right.IsValueType; 383 } 384 } 385 386 // 387 // For a userdefined type T which has op_False defined and L, R are 388 // nullable, (L AndAlso R) is computed as: 389 // 390 // L.HasValue 391 // ? T.op_False(L.GetValueOrDefault()) 392 // ? L 393 // : R.HasValue 394 // ? (T?)(T.op_BitwiseAnd(L.GetValueOrDefault(), R.GetValueOrDefault())) 395 // : null 396 // : null 397 // 398 // For a userdefined type T which has op_True defined and L, R are 399 // nullable, (L OrElse R) is computed as: 400 // 401 // L.HasValue 402 // ? T.op_True(L.GetValueOrDefault()) 403 // ? L 404 // : R.HasValue 405 // ? (T?)(T.op_BitwiseOr(L.GetValueOrDefault(), R.GetValueOrDefault())) 406 // : null 407 // : null 408 // 409 // 410 // This is the same behavior as VB. If you think about it, it makes 411 // sense: it's combining the normal pattern for short-circuiting 412 // operators, with the normal pattern for lifted operations: if either 413 // of the operands is null, the result is also null. 414 // ReduceUserdefinedLifted()415 internal Expression ReduceUserdefinedLifted() { 416 Debug.Assert(IsLiftedLogical); 417 418 var left = Parameter(_left.Type, "left"); 419 var right = Parameter(Right.Type, "right"); 420 string opName = NodeType == ExpressionType.AndAlso ? "op_False" : "op_True"; 421 MethodInfo opTrueFalse = TypeUtils.GetBooleanOperator(Method.DeclaringType, opName); 422 Debug.Assert(opTrueFalse != null); 423 424 return Block( 425 new[] { left }, 426 Assign(left, _left), 427 Condition( 428 Property(left, "HasValue"), 429 Condition( 430 Call(opTrueFalse, Call(left, "GetValueOrDefault", null)), 431 left, 432 Block( 433 new[] { right }, 434 Assign(right, _right), 435 Condition( 436 Property(right, "HasValue"), 437 Convert( 438 Call( 439 Method, 440 Call(left, "GetValueOrDefault", null), 441 Call(right, "GetValueOrDefault", null) 442 ), 443 Type 444 ), 445 Constant(null, Type) 446 ) 447 ) 448 ), 449 Constant(null, Type) 450 ) 451 ); 452 } 453 } 454 455 // Optimized representation of simple logical expressions: 456 // && || == != > < >= <= 457 internal sealed class LogicalBinaryExpression : BinaryExpression { 458 private readonly ExpressionType _nodeType; 459 LogicalBinaryExpression(ExpressionType nodeType, Expression left, Expression right)460 internal LogicalBinaryExpression(ExpressionType nodeType, Expression left, Expression right) 461 : base(left, right) { 462 _nodeType = nodeType; 463 } 464 465 public sealed override Type Type { 466 get { return typeof(bool); } 467 } 468 469 public sealed override ExpressionType NodeType { 470 get { return _nodeType; } 471 } 472 } 473 474 // Optimized assignment node, only holds onto children 475 internal sealed class AssignBinaryExpression : BinaryExpression { AssignBinaryExpression(Expression left, Expression right)476 internal AssignBinaryExpression(Expression left, Expression right) 477 : base(left, right) { 478 } 479 480 public sealed override Type Type { 481 get { return Left.Type; } 482 } 483 484 public sealed override ExpressionType NodeType { 485 get { return ExpressionType.Assign; } 486 } 487 } 488 489 // Coalesce with conversion 490 // This is not a frequently used node, but rather we want to save every 491 // other BinaryExpression from holding onto the null conversion lambda 492 internal sealed class CoalesceConversionBinaryExpression : BinaryExpression { 493 private readonly LambdaExpression _conversion; 494 CoalesceConversionBinaryExpression(Expression left, Expression right, LambdaExpression conversion)495 internal CoalesceConversionBinaryExpression(Expression left, Expression right, LambdaExpression conversion) 496 : base(left, right) { 497 _conversion = conversion; 498 } 499 GetConversion()500 internal override LambdaExpression GetConversion() { 501 return _conversion; 502 } 503 504 public sealed override ExpressionType NodeType { 505 get { return ExpressionType.Coalesce; } 506 } 507 508 public sealed override Type Type { 509 get { return Right.Type; } 510 } 511 } 512 513 // OpAssign with conversion 514 // This is not a frequently used node, but rather we want to save every 515 // other BinaryExpression from holding onto the null conversion lambda 516 internal sealed class OpAssignMethodConversionBinaryExpression : MethodBinaryExpression { 517 private readonly LambdaExpression _conversion; 518 OpAssignMethodConversionBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion)519 internal OpAssignMethodConversionBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion) 520 : base(nodeType, left, right, type, method) { 521 _conversion = conversion; 522 } 523 GetConversion()524 internal override LambdaExpression GetConversion() { 525 return _conversion; 526 } 527 } 528 529 // Class that handles most binary expressions 530 // If needed, it can be optimized even more (often Type == left.Type) 531 internal class SimpleBinaryExpression : BinaryExpression { 532 private readonly ExpressionType _nodeType; 533 private readonly Type _type; 534 SimpleBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type)535 internal SimpleBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type) 536 : base(left, right) { 537 _nodeType = nodeType; 538 _type = type; 539 } 540 541 public sealed override ExpressionType NodeType { 542 get { return _nodeType; } 543 } 544 545 public sealed override Type Type { 546 get { return _type; } 547 } 548 } 549 550 // Class that handles binary expressions with a method 551 // If needed, it can be optimized even more (often Type == method.ReturnType) 552 internal class MethodBinaryExpression : SimpleBinaryExpression { 553 private readonly MethodInfo _method; 554 MethodBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method)555 internal MethodBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method) 556 : base(nodeType, left, right, type) { 557 _method = method; 558 } 559 GetMethod()560 internal override MethodInfo GetMethod() { 561 return _method; 562 } 563 } 564 565 public partial class Expression { 566 567 #region Assign 568 569 /// <summary> 570 /// Creates a <see cref="BinaryExpression"/> that represents an assignment operation. 571 /// </summary> 572 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 573 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 574 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see ref="F:ExpressionType.Assign"/> 575 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. 576 /// </returns> Assign(Expression left, Expression right)577 public static BinaryExpression Assign(Expression left, Expression right) { 578 RequiresCanWrite(left, "left"); 579 RequiresCanRead(right, "right"); 580 TypeUtils.ValidateType(left.Type); 581 TypeUtils.ValidateType(right.Type); 582 if (!TypeUtils.AreReferenceAssignable(left.Type, right.Type)) { 583 throw Error.ExpressionTypeDoesNotMatchAssignment(right.Type, left.Type); 584 } 585 return new AssignBinaryExpression(left, right); 586 } 587 588 #endregion 589 590 GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull)591 private static BinaryExpression GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) { 592 // try exact match first 593 MethodInfo method = GetUserDefinedBinaryOperator(binaryType, left.Type, right.Type, name); 594 if (method != null) { 595 return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method); 596 } 597 // try lifted call 598 if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type)) { 599 Type nnLeftType = TypeUtils.GetNonNullableType(left.Type); 600 Type nnRightType = TypeUtils.GetNonNullableType(right.Type); 601 method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name); 602 if (method != null && method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) { 603 if (method.ReturnType != typeof(bool) || liftToNull) { 604 return new MethodBinaryExpression(binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method); 605 } else { 606 return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method); 607 } 608 } 609 } 610 return null; 611 } 612 613 GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull)614 private static BinaryExpression GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull) { 615 System.Diagnostics.Debug.Assert(method != null); 616 ValidateOperator(method); 617 ParameterInfo[] pms = method.GetParametersCached(); 618 if (pms.Length != 2) 619 throw Error.IncorrectNumberOfMethodCallArguments(method); 620 if (ParameterIsAssignable(pms[0], left.Type) && ParameterIsAssignable(pms[1], right.Type)) { 621 ValidateParamswithOperandsOrThrow(pms[0].ParameterType, left.Type, binaryType, method.Name); 622 ValidateParamswithOperandsOrThrow(pms[1].ParameterType, right.Type, binaryType, method.Name); 623 return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method); 624 625 } 626 // check for lifted call 627 if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type) && 628 ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) && 629 ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right.Type)) && 630 method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) { 631 if (method.ReturnType != typeof(bool) || liftToNull) { 632 return new MethodBinaryExpression(binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method); 633 } else { 634 return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method); 635 } 636 } 637 throw Error.OperandTypesDoNotMatchParameters(binaryType, method.Name); 638 } 639 GetMethodBasedAssignOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression conversion, bool liftToNull)640 private static BinaryExpression GetMethodBasedAssignOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression conversion, bool liftToNull) { 641 BinaryExpression b = GetMethodBasedBinaryOperator(binaryType, left, right, method, liftToNull); 642 if (conversion == null) { 643 // return type must be assignable back to the left type 644 if (!TypeUtils.AreReferenceAssignable(left.Type, b.Type)) { 645 throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name); 646 } 647 } else { 648 // add the conversion to the result 649 ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType); 650 b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion); 651 } 652 return b; 653 } 654 655 GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull)656 private static BinaryExpression GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) { 657 BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, name, left, right, liftToNull); 658 if (b != null) { 659 ParameterInfo[] pis = b.Method.GetParametersCached(); 660 ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, binaryType, name); 661 ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, binaryType, name); 662 return b; 663 } 664 throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type); 665 } 666 GetUserDefinedAssignOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, LambdaExpression conversion, bool liftToNull)667 private static BinaryExpression GetUserDefinedAssignOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, LambdaExpression conversion, bool liftToNull) { 668 BinaryExpression b = GetUserDefinedBinaryOperatorOrThrow(binaryType, name, left, right, liftToNull); 669 if (conversion == null) { 670 // return type must be assignable back to the left type 671 if (!TypeUtils.AreReferenceAssignable(left.Type, b.Type)) { 672 throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name); 673 } 674 } else { 675 // add the conversion to the result 676 ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType); 677 b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion); 678 } 679 return b; 680 } 681 682 GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name)683 private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) { 684 // 685 686 Type[] types = new Type[] { leftType, rightType }; 687 Type nnLeftType = TypeUtils.GetNonNullableType(leftType); 688 Type nnRightType = TypeUtils.GetNonNullableType(rightType); 689 BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; 690 MethodInfo method = nnLeftType.GetMethodValidated(name, flags, null, types, null); 691 if (method == null && !TypeUtils.AreEquivalent(leftType, rightType)) { 692 method = nnRightType.GetMethodValidated(name, flags, null, types, null); 693 } 694 695 if (IsLiftingConditionalLogicalOperator(leftType, rightType, method, binaryType)) { 696 method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name); 697 } 698 return method; 699 } 700 701 IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType)702 private static bool IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType) { 703 return TypeUtils.IsNullableType(right) && 704 TypeUtils.IsNullableType(left) && 705 method == null && 706 (binaryType == ExpressionType.AndAlso || binaryType == ExpressionType.OrElse); 707 } 708 709 ParameterIsAssignable(ParameterInfo pi, Type argType)710 internal static bool ParameterIsAssignable(ParameterInfo pi, Type argType) { 711 Type pType = pi.ParameterType; 712 if (pType.IsByRef) 713 pType = pType.GetElementType(); 714 return TypeUtils.AreReferenceAssignable(pType, argType); 715 } 716 717 ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name)718 private static void ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name) { 719 if (TypeUtils.IsNullableType(paramType) && !TypeUtils.IsNullableType(operandType)) { 720 throw Error.OperandTypesDoNotMatchParameters(exprType, name); 721 } 722 } 723 724 ValidateOperator(MethodInfo method)725 private static void ValidateOperator(MethodInfo method) { 726 System.Diagnostics.Debug.Assert(method != null); 727 ValidateMethodInfo(method); 728 if (!method.IsStatic) 729 throw Error.UserDefinedOperatorMustBeStatic(method); 730 if (method.ReturnType == typeof(void)) 731 throw Error.UserDefinedOperatorMustNotBeVoid(method); 732 } 733 734 ValidateMethodInfo(MethodInfo method)735 private static void ValidateMethodInfo(MethodInfo method) { 736 if (method.IsGenericMethodDefinition) 737 throw Error.MethodIsGeneric(method); 738 if (method.ContainsGenericParameters) 739 throw Error.MethodContainsGenericParameters(method); 740 } 741 742 IsNullComparison(Expression left, Expression right)743 private static bool IsNullComparison(Expression left, Expression right) { 744 // If we have x==null, x!=null, null==x or null!=x where x is 745 // nullable but not null, then this is treated as a call to x.HasValue 746 // and is legal even if there is no equality operator defined on the 747 // type of x. 748 if (IsNullConstant(left) && !IsNullConstant(right) && TypeUtils.IsNullableType(right.Type)) { 749 return true; 750 } 751 if (IsNullConstant(right) && !IsNullConstant(left) && TypeUtils.IsNullableType(left.Type)) { 752 return true; 753 } 754 return false; 755 } 756 757 758 // Note: this has different meaning than ConstantCheck.IsNull 759 // That function attempts to determine if the result of a tree will be 760 // null at runtime. This function is used at tree construction time and 761 // only looks for a ConstantExpression with a null Value. It can't 762 // become "smarter" or that would break tree construction. IsNullConstant(Expression e)763 private static bool IsNullConstant(Expression e) { 764 var c = e as ConstantExpression; 765 return c != null && c.Value == null; 766 } 767 768 ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method)769 private static void ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method) { 770 ValidateOperator(method); 771 ParameterInfo[] pms = method.GetParametersCached(); 772 if (pms.Length != 2) 773 throw Error.IncorrectNumberOfMethodCallArguments(method); 774 if (!ParameterIsAssignable(pms[0], left)) { 775 if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left)))) 776 throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name); 777 } 778 if (!ParameterIsAssignable(pms[1], right)) { 779 if (!(TypeUtils.IsNullableType(right) && ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right)))) 780 throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name); 781 } 782 if (pms[0].ParameterType != pms[1].ParameterType) { 783 throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name); 784 } 785 if (method.ReturnType != pms[0].ParameterType) { 786 throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name); 787 } 788 if (IsValidLiftedConditionalLogicalOperator(left, right, pms)) { 789 left = TypeUtils.GetNonNullableType(left); 790 right = TypeUtils.GetNonNullableType(left); 791 } 792 MethodInfo opTrue = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_True"); 793 MethodInfo opFalse = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_False"); 794 if (opTrue == null || opTrue.ReturnType != typeof(bool) || 795 opFalse == null || opFalse.ReturnType != typeof(bool)) { 796 throw Error.LogicalOperatorMustHaveBooleanOperators(nodeType, method.Name); 797 } 798 VerifyOpTrueFalse(nodeType, left, opFalse); 799 VerifyOpTrueFalse(nodeType, left, opTrue); 800 } 801 VerifyOpTrueFalse(ExpressionType nodeType, Type left, MethodInfo opTrue)802 private static void VerifyOpTrueFalse(ExpressionType nodeType, Type left, MethodInfo opTrue) { 803 ParameterInfo[] pmsOpTrue = opTrue.GetParametersCached(); 804 if (pmsOpTrue.Length != 1) 805 throw Error.IncorrectNumberOfMethodCallArguments(opTrue); 806 807 if (!ParameterIsAssignable(pmsOpTrue[0], left)) { 808 if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pmsOpTrue[0], TypeUtils.GetNonNullableType(left)))) 809 throw Error.OperandTypesDoNotMatchParameters(nodeType, opTrue.Name); 810 } 811 } 812 IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms)813 private static bool IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms) { 814 return TypeUtils.AreEquivalent(left, right) && 815 TypeUtils.IsNullableType(right) && 816 TypeUtils.AreEquivalent(pms[1].ParameterType, TypeUtils.GetNonNullableType(right)); 817 } 818 819 820 /// <summary> 821 /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. 822 /// </summary> 823 /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> 824 /// <param name="left">An Expression that represents the left operand.</param> 825 /// <param name="right">An Expression that represents the right operand.</param> 826 /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> MakeBinary(ExpressionType binaryType, Expression left, Expression right)827 public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right) { 828 return MakeBinary(binaryType, left, right, false, null, null); 829 } 830 831 /// <summary> 832 /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. 833 /// </summary> 834 /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> 835 /// <param name="left">An Expression that represents the left operand.</param> 836 /// <param name="right">An Expression that represents the right operand.</param> 837 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 838 /// <param name="method">A MethodInfo that specifies the implementing method.</param> 839 /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)840 public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method) { 841 return MakeBinary(binaryType, left, right, liftToNull, method, null); 842 } 843 844 /// 845 /// <summary> 846 /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. 847 /// </summary> 848 /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> 849 /// <param name="left">An Expression that represents the left operand.</param> 850 /// <param name="right">An Expression that represents the right operand.</param> 851 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 852 /// <param name="method">A MethodInfo that specifies the implementing method.</param> 853 /// <param name="conversion">A LambdaExpression that represents a type conversion function. This parameter is used if binaryType is Coalesce or compound assignment.</param> 854 /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> 855 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)856 public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion) { 857 switch (binaryType) { 858 case ExpressionType.Add: 859 return Add(left, right, method); 860 case ExpressionType.AddChecked: 861 return AddChecked(left, right, method); 862 case ExpressionType.Subtract: 863 return Subtract(left, right, method); 864 case ExpressionType.SubtractChecked: 865 return SubtractChecked(left, right, method); 866 case ExpressionType.Multiply: 867 return Multiply(left, right, method); 868 case ExpressionType.MultiplyChecked: 869 return MultiplyChecked(left, right, method); 870 case ExpressionType.Divide: 871 return Divide(left, right, method); 872 case ExpressionType.Modulo: 873 return Modulo(left, right, method); 874 case ExpressionType.Power: 875 return Power(left, right, method); 876 case ExpressionType.And: 877 return And(left, right, method); 878 case ExpressionType.AndAlso: 879 return AndAlso(left, right, method); 880 case ExpressionType.Or: 881 return Or(left, right, method); 882 case ExpressionType.OrElse: 883 return OrElse(left, right, method); 884 case ExpressionType.LessThan: 885 return LessThan(left, right, liftToNull, method); 886 case ExpressionType.LessThanOrEqual: 887 return LessThanOrEqual(left, right, liftToNull, method); 888 case ExpressionType.GreaterThan: 889 return GreaterThan(left, right, liftToNull, method); 890 case ExpressionType.GreaterThanOrEqual: 891 return GreaterThanOrEqual(left, right, liftToNull, method); 892 case ExpressionType.Equal: 893 return Equal(left, right, liftToNull, method); 894 case ExpressionType.NotEqual: 895 return NotEqual(left, right, liftToNull, method); 896 case ExpressionType.ExclusiveOr: 897 return ExclusiveOr(left, right, method); 898 case ExpressionType.Coalesce: 899 return Coalesce(left, right, conversion); 900 case ExpressionType.ArrayIndex: 901 return ArrayIndex(left, right); 902 case ExpressionType.RightShift: 903 return RightShift(left, right, method); 904 case ExpressionType.LeftShift: 905 return LeftShift(left, right, method); 906 case ExpressionType.Assign: 907 return Assign(left, right); 908 case ExpressionType.AddAssign: 909 return AddAssign(left, right, method, conversion); 910 case ExpressionType.AndAssign: 911 return AndAssign(left, right, method, conversion); 912 case ExpressionType.DivideAssign: 913 return DivideAssign(left, right, method, conversion); 914 case ExpressionType.ExclusiveOrAssign: 915 return ExclusiveOrAssign(left, right, method, conversion); 916 case ExpressionType.LeftShiftAssign: 917 return LeftShiftAssign(left, right, method, conversion); 918 case ExpressionType.ModuloAssign: 919 return ModuloAssign(left, right, method, conversion); 920 case ExpressionType.MultiplyAssign: 921 return MultiplyAssign(left, right, method, conversion); 922 case ExpressionType.OrAssign: 923 return OrAssign(left, right, method, conversion); 924 case ExpressionType.PowerAssign: 925 return PowerAssign(left, right, method, conversion); 926 case ExpressionType.RightShiftAssign: 927 return RightShiftAssign(left, right, method, conversion); 928 case ExpressionType.SubtractAssign: 929 return SubtractAssign(left, right, method, conversion); 930 case ExpressionType.AddAssignChecked: 931 return AddAssignChecked(left, right, method, conversion); 932 case ExpressionType.SubtractAssignChecked: 933 return SubtractAssignChecked(left, right, method, conversion); 934 case ExpressionType.MultiplyAssignChecked: 935 return MultiplyAssignChecked(left, right, method, conversion); 936 default: 937 throw Error.UnhandledBinary(binaryType); 938 } 939 } 940 941 #region Equality Operators 942 943 944 /// <summary> 945 /// Creates a <see cref="BinaryExpression"/> that represents an equality comparison. 946 /// </summary> 947 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 948 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 949 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 950 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Equal(Expression left, Expression right)951 public static BinaryExpression Equal(Expression left, Expression right) { 952 return Equal(left, right, false, null); 953 } 954 955 /// <summary> 956 /// Creates a <see cref="BinaryExpression"/> that represents an equality comparison. 957 /// </summary> 958 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 959 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 960 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 961 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 962 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 963 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 964 /// </returns> Equal(Expression left, Expression right, bool liftToNull, MethodInfo method)965 public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) { 966 RequiresCanRead(left, "left"); 967 RequiresCanRead(right, "right"); 968 if (method == null) { 969 return GetEqualityComparisonOperator(ExpressionType.Equal, "op_Equality", left, right, liftToNull); 970 } 971 return GetMethodBasedBinaryOperator(ExpressionType.Equal, left, right, method, liftToNull); 972 } 973 974 /// <summary> 975 /// Creates a <see cref="BinaryExpression"/> that represents a reference equality comparison. 976 /// </summary> 977 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 978 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 979 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 980 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. 981 /// </returns> ReferenceEqual(Expression left, Expression right)982 public static BinaryExpression ReferenceEqual(Expression left, Expression right) { 983 RequiresCanRead(left, "left"); 984 RequiresCanRead(right, "right"); 985 if (TypeUtils.HasReferenceEquality(left.Type, right.Type)) { 986 return new LogicalBinaryExpression(ExpressionType.Equal, left, right); 987 } 988 throw Error.ReferenceEqualityNotDefined(left.Type, right.Type); 989 } 990 991 /// <summary> 992 /// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison. 993 /// </summary> 994 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 995 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 996 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 997 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> NotEqual(Expression left, Expression right)998 public static BinaryExpression NotEqual(Expression left, Expression right) { 999 return NotEqual(left, right, false, null); 1000 } 1001 1002 /// <summary> 1003 /// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison. 1004 /// </summary> 1005 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1006 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1007 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 1008 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1009 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 1010 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1011 /// </returns> NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method)1012 public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) { 1013 RequiresCanRead(left, "left"); 1014 RequiresCanRead(right, "right"); 1015 if (method == null) { 1016 return GetEqualityComparisonOperator(ExpressionType.NotEqual, "op_Inequality", left, right, liftToNull); 1017 } 1018 return GetMethodBasedBinaryOperator(ExpressionType.NotEqual, left, right, method, liftToNull); 1019 } 1020 1021 /// <summary> 1022 /// Creates a <see cref="BinaryExpression"/> that represents a reference inequality comparison. 1023 /// </summary> 1024 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1025 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1026 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 1027 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. 1028 /// </returns> ReferenceNotEqual(Expression left, Expression right)1029 public static BinaryExpression ReferenceNotEqual(Expression left, Expression right) { 1030 RequiresCanRead(left, "left"); 1031 RequiresCanRead(right, "right"); 1032 if (TypeUtils.HasReferenceEquality(left.Type, right.Type)) { 1033 return new LogicalBinaryExpression(ExpressionType.NotEqual, left, right); 1034 } 1035 throw Error.ReferenceEqualityNotDefined(left.Type, right.Type); 1036 } 1037 GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull)1038 private static BinaryExpression GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) { 1039 // known comparison - numeric types, bools, object, enums 1040 if (left.Type == right.Type && (TypeUtils.IsNumeric(left.Type) || 1041 left.Type == typeof(object) || 1042 TypeUtils.IsBool(left.Type) || 1043 TypeUtils.GetNonNullableType(left.Type).IsEnum)) { 1044 if (TypeUtils.IsNullableType(left.Type) && liftToNull) { 1045 return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); 1046 } else { 1047 return new LogicalBinaryExpression(binaryType, left, right); 1048 } 1049 } 1050 // look for user defined operator 1051 BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, opName, left, right, liftToNull); 1052 if (b != null) { 1053 return b; 1054 } 1055 if (TypeUtils.HasBuiltInEqualityOperator(left.Type, right.Type) || IsNullComparison(left, right)) { 1056 if (TypeUtils.IsNullableType(left.Type) && liftToNull) { 1057 return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); 1058 } else { 1059 return new LogicalBinaryExpression(binaryType, left, right); 1060 } 1061 } 1062 throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type); 1063 } 1064 1065 #endregion 1066 1067 #region Comparison Expressions 1068 1069 1070 /// <summary> 1071 /// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison. 1072 /// </summary> 1073 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1074 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1075 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> 1076 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> GreaterThan(Expression left, Expression right)1077 public static BinaryExpression GreaterThan(Expression left, Expression right) { 1078 return GreaterThan(left, right, false, null); 1079 } 1080 1081 /// <summary> 1082 /// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison. 1083 /// </summary> 1084 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1085 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1086 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1087 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 1088 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> 1089 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1090 /// </returns> GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method)1091 public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) { 1092 RequiresCanRead(left, "left"); 1093 RequiresCanRead(right, "right"); 1094 if (method == null) { 1095 return GetComparisonOperator(ExpressionType.GreaterThan, "op_GreaterThan", left, right, liftToNull); 1096 } 1097 return GetMethodBasedBinaryOperator(ExpressionType.GreaterThan, left, right, method, liftToNull); 1098 } 1099 1100 /// <summary> 1101 /// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison. 1102 /// </summary> 1103 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1104 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1105 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> 1106 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> 1107 LessThan(Expression left, Expression right)1108 public static BinaryExpression LessThan(Expression left, Expression right) { 1109 return LessThan(left, right, false, null); 1110 } 1111 1112 /// <summary> 1113 /// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison. 1114 /// </summary> 1115 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1116 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1117 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1118 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 1119 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> 1120 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1121 /// </returns> LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method)1122 public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) { 1123 RequiresCanRead(left, "left"); 1124 RequiresCanRead(right, "right"); 1125 if (method == null) { 1126 return GetComparisonOperator(ExpressionType.LessThan, "op_LessThan", left, right, liftToNull); 1127 } 1128 return GetMethodBasedBinaryOperator(ExpressionType.LessThan, left, right, method, liftToNull); 1129 } 1130 1131 1132 /// <summary> 1133 /// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison. 1134 /// </summary> 1135 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1136 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1137 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> 1138 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> GreaterThanOrEqual(Expression left, Expression right)1139 public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) { 1140 return GreaterThanOrEqual(left, right, false, null); 1141 } 1142 1143 /// <summary> 1144 /// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison. 1145 /// </summary> 1146 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1147 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1148 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1149 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 1150 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> 1151 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1152 /// </returns> GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method)1153 public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) { 1154 RequiresCanRead(left, "left"); 1155 RequiresCanRead(right, "right"); 1156 if (method == null) { 1157 return GetComparisonOperator(ExpressionType.GreaterThanOrEqual, "op_GreaterThanOrEqual", left, right, liftToNull); 1158 } 1159 return GetMethodBasedBinaryOperator(ExpressionType.GreaterThanOrEqual, left, right, method, liftToNull); 1160 } 1161 1162 1163 /// <summary> 1164 /// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison. 1165 /// </summary> 1166 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1167 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1168 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> 1169 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> LessThanOrEqual(Expression left, Expression right)1170 public static BinaryExpression LessThanOrEqual(Expression left, Expression right) { 1171 return LessThanOrEqual(left, right, false, null); 1172 } 1173 1174 /// <summary> 1175 /// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison. 1176 /// </summary> 1177 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1178 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1179 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1180 /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> 1181 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> 1182 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1183 /// </returns> LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method)1184 public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) { 1185 RequiresCanRead(left, "left"); 1186 RequiresCanRead(right, "right"); 1187 if (method == null) { 1188 return GetComparisonOperator(ExpressionType.LessThanOrEqual, "op_LessThanOrEqual", left, right, liftToNull); 1189 } 1190 return GetMethodBasedBinaryOperator(ExpressionType.LessThanOrEqual, left, right, method, liftToNull); 1191 } 1192 1193 GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull)1194 private static BinaryExpression GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) { 1195 if (left.Type == right.Type && TypeUtils.IsNumeric(left.Type)) { 1196 if (TypeUtils.IsNullableType(left.Type) && liftToNull) { 1197 return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); 1198 } else { 1199 return new LogicalBinaryExpression(binaryType, left, right); 1200 } 1201 } 1202 return GetUserDefinedBinaryOperatorOrThrow(binaryType, opName, left, right, liftToNull); 1203 } 1204 1205 #endregion 1206 1207 #region Boolean Expressions 1208 1209 1210 /// <summary> 1211 /// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to. 1212 /// </summary> 1213 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1214 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1215 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> 1216 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> AndAlso(Expression left, Expression right)1217 public static BinaryExpression AndAlso(Expression left, Expression right) { 1218 return AndAlso(left, right, null); 1219 } 1220 1221 /// <summary> 1222 /// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to. 1223 /// </summary> 1224 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1225 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1226 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1227 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> 1228 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1229 /// </returns> AndAlso(Expression left, Expression right, MethodInfo method)1230 public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) { 1231 RequiresCanRead(left, "left"); 1232 RequiresCanRead(right, "right"); 1233 Type returnType; 1234 if (method == null) { 1235 if (left.Type == right.Type) { 1236 if (left.Type == typeof(bool)) { 1237 return new LogicalBinaryExpression(ExpressionType.AndAlso, left, right); 1238 } else if (left.Type == typeof(bool?)) { 1239 return new SimpleBinaryExpression(ExpressionType.AndAlso, left, right, left.Type); 1240 } 1241 } 1242 method = GetUserDefinedBinaryOperator(ExpressionType.AndAlso, left.Type, right.Type, "op_BitwiseAnd"); 1243 if (method != null) { 1244 ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method); 1245 returnType = (TypeUtils.IsNullableType(left.Type) && TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left.Type))) ? left.Type : method.ReturnType; 1246 return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method); 1247 } 1248 throw Error.BinaryOperatorNotDefined(ExpressionType.AndAlso, left.Type, right.Type); 1249 } 1250 ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method); 1251 returnType = (TypeUtils.IsNullableType(left.Type) && TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left.Type))) ? left.Type : method.ReturnType; 1252 return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method); 1253 } 1254 1255 1256 /// <summary> 1257 /// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to. 1258 /// </summary> 1259 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1260 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1261 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> 1262 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> OrElse(Expression left, Expression right)1263 public static BinaryExpression OrElse(Expression left, Expression right) { 1264 return OrElse(left, right, null); 1265 } 1266 1267 /// <summary> 1268 /// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to. 1269 /// </summary> 1270 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1271 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1272 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1273 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> 1274 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1275 /// </returns> OrElse(Expression left, Expression right, MethodInfo method)1276 public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) { 1277 RequiresCanRead(left, "left"); 1278 RequiresCanRead(right, "right"); 1279 Type returnType; 1280 if (method == null) { 1281 if (left.Type == right.Type) { 1282 if (left.Type == typeof(bool)) { 1283 return new LogicalBinaryExpression(ExpressionType.OrElse, left, right); 1284 } else if (left.Type == typeof(bool?)) { 1285 return new SimpleBinaryExpression(ExpressionType.OrElse, left, right, left.Type); 1286 } 1287 } 1288 method = GetUserDefinedBinaryOperator(ExpressionType.OrElse, left.Type, right.Type, "op_BitwiseOr"); 1289 if (method != null) { 1290 ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method); 1291 returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType; 1292 return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method); 1293 } 1294 throw Error.BinaryOperatorNotDefined(ExpressionType.OrElse, left.Type, right.Type); 1295 } 1296 ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method); 1297 returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType; 1298 return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method); 1299 } 1300 1301 #endregion 1302 1303 #region Coalescing Expressions 1304 1305 1306 /// <summary> 1307 /// Creates a BinaryExpression that represents a coalescing operation. 1308 /// </summary> 1309 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1310 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1311 /// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left and Right properties set to the specified values.</returns> Coalesce(Expression left, Expression right)1312 public static BinaryExpression Coalesce(Expression left, Expression right) { 1313 return Coalesce(left, right, null); 1314 } 1315 1316 1317 /// <summary> 1318 /// Creates a BinaryExpression that represents a coalescing operation. 1319 /// </summary> 1320 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1321 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1322 /// <param name="conversion">A LambdaExpression to set the Conversion property equal to.</param> 1323 /// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left, Right and Conversion properties set to the specified values. 1324 /// </returns> Coalesce(Expression left, Expression right, LambdaExpression conversion)1325 public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) { 1326 RequiresCanRead(left, "left"); 1327 RequiresCanRead(right, "right"); 1328 1329 if (conversion == null) { 1330 Type resultType = ValidateCoalesceArgTypes(left.Type, right.Type); 1331 return new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, resultType); 1332 } 1333 1334 if (left.Type.IsValueType && !TypeUtils.IsNullableType(left.Type)) { 1335 throw Error.CoalesceUsedOnNonNullType(); 1336 } 1337 1338 Type delegateType = conversion.Type; 1339 Debug.Assert(typeof(System.MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(System.MulticastDelegate)); 1340 MethodInfo method = delegateType.GetMethod("Invoke"); 1341 if (method.ReturnType == typeof(void)) { 1342 throw Error.UserDefinedOperatorMustNotBeVoid(conversion); 1343 } 1344 ParameterInfo[] pms = method.GetParametersCached(); 1345 Debug.Assert(pms.Length == conversion.Parameters.Count); 1346 if (pms.Length != 1) { 1347 throw Error.IncorrectNumberOfMethodCallArguments(conversion); 1348 } 1349 // The return type must match exactly. 1350 // 1351 1352 1353 if (!TypeUtils.AreEquivalent(method.ReturnType, right.Type)) { 1354 throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString()); 1355 } 1356 // The parameter of the conversion lambda must either be assignable 1357 // from the erased or unerased type of the left hand side. 1358 if (!ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) && 1359 !ParameterIsAssignable(pms[0], left.Type)) { 1360 throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString()); 1361 } 1362 return new CoalesceConversionBinaryExpression(left, right, conversion); 1363 } 1364 1365 ValidateCoalesceArgTypes(Type left, Type right)1366 private static Type ValidateCoalesceArgTypes(Type left, Type right) { 1367 Type leftStripped = TypeUtils.GetNonNullableType(left); 1368 if (left.IsValueType && !TypeUtils.IsNullableType(left)) { 1369 throw Error.CoalesceUsedOnNonNullType(); 1370 } else if (TypeUtils.IsNullableType(left) && TypeUtils.IsImplicitlyConvertible(right, leftStripped)) { 1371 return leftStripped; 1372 } else if (TypeUtils.IsImplicitlyConvertible(right, left)) { 1373 return left; 1374 } else if (TypeUtils.IsImplicitlyConvertible(leftStripped, right)) { 1375 return right; 1376 } else { 1377 throw Error.ArgumentTypesMustMatch(); 1378 } 1379 } 1380 1381 1382 1383 #endregion 1384 1385 #region Arithmetic Expressions 1386 1387 1388 /// <summary> 1389 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking. 1390 /// </summary> 1391 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1392 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1393 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> 1394 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Add(Expression left, Expression right)1395 public static BinaryExpression Add(Expression left, Expression right) { 1396 return Add(left, right, null); 1397 } 1398 1399 /// <summary> 1400 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking. 1401 /// </summary> 1402 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1403 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1404 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1405 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> 1406 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1407 /// </returns> Add(Expression left, Expression right, MethodInfo method)1408 public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) { 1409 RequiresCanRead(left, "left"); 1410 RequiresCanRead(right, "right"); 1411 if (method == null) { 1412 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1413 return new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type); 1414 } 1415 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true); 1416 } 1417 return GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true); 1418 } 1419 1420 1421 /// <summary> 1422 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. 1423 /// </summary> 1424 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1425 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1426 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 1427 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> AddAssign(Expression left, Expression right)1428 public static BinaryExpression AddAssign(Expression left, Expression right) { 1429 return AddAssign(left, right, null, null); 1430 } 1431 1432 /// <summary> 1433 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. 1434 /// </summary> 1435 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1436 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1437 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1438 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 1439 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1440 /// </returns> AddAssign(Expression left, Expression right, MethodInfo method)1441 public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method) { 1442 return AddAssign(left, right, method, null); 1443 } 1444 1445 /// <summary> 1446 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. 1447 /// </summary> 1448 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1449 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1450 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1451 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1452 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 1453 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1454 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1455 /// </returns> 1456 AddAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1457 public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1458 RequiresCanRead(left, "left"); 1459 RequiresCanWrite(left, "left"); 1460 RequiresCanRead(right, "right"); 1461 if (method == null) { 1462 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1463 // conversion is not supported for binary ops on arithmetic types without operator overloading 1464 if (conversion != null) { 1465 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1466 } 1467 return new SimpleBinaryExpression(ExpressionType.AddAssign, left, right, left.Type); 1468 } 1469 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssign, "op_Addition", left, right, conversion, true); 1470 } 1471 return GetMethodBasedAssignOperator(ExpressionType.AddAssign, left, right, method, conversion, true); 1472 } 1473 ValidateOpAssignConversionLambda(LambdaExpression conversion, Expression left, MethodInfo method, ExpressionType nodeType)1474 private static void ValidateOpAssignConversionLambda(LambdaExpression conversion, Expression left, MethodInfo method, ExpressionType nodeType) { 1475 Type delegateType = conversion.Type; 1476 Debug.Assert(typeof(System.MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(System.MulticastDelegate)); 1477 MethodInfo mi = delegateType.GetMethod("Invoke"); 1478 ParameterInfo[] pms = mi.GetParametersCached(); 1479 Debug.Assert(pms.Length == conversion.Parameters.Count); 1480 if (pms.Length != 1) { 1481 throw Error.IncorrectNumberOfMethodCallArguments(conversion); 1482 } 1483 if (!TypeUtils.AreEquivalent(mi.ReturnType, left.Type)) { 1484 throw Error.OperandTypesDoNotMatchParameters(nodeType, conversion.ToString()); 1485 } 1486 if (method != null) { 1487 // The parameter type of conversion lambda must be the same as the return type of the overload method 1488 if (!TypeUtils.AreEquivalent(pms[0].ParameterType, method.ReturnType)) { 1489 throw Error.OverloadOperatorTypeDoesNotMatchConversionType(nodeType, conversion.ToString()); 1490 } 1491 } 1492 } 1493 1494 1495 /// <summary> 1496 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. 1497 /// </summary> 1498 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1499 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1500 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to 1501 /// <see cref="F:ExpressionType.AddAssignChecked"/> and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> 1502 /// properties set to the specified values. 1503 /// </returns> AddAssignChecked(Expression left, Expression right)1504 public static BinaryExpression AddAssignChecked(Expression left, Expression right) { 1505 return AddAssignChecked(left, right, null); 1506 } 1507 1508 /// <summary> 1509 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. 1510 /// </summary> 1511 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1512 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1513 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1514 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> 1515 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1516 /// </returns> AddAssignChecked(Expression left, Expression right, MethodInfo method)1517 public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method) { 1518 return AddAssignChecked(left, right, method, null); 1519 } 1520 1521 /// <summary> 1522 /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. 1523 /// </summary> 1524 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1525 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1526 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1527 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1528 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> 1529 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1530 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1531 /// </returns> AddAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1532 public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1533 RequiresCanRead(left, "left"); 1534 RequiresCanWrite(left, "left"); 1535 RequiresCanRead(right, "right"); 1536 1537 if (method == null) { 1538 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1539 // conversion is not supported for binary ops on arithmetic types without operator overloading 1540 if (conversion != null) { 1541 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1542 } 1543 return new SimpleBinaryExpression(ExpressionType.AddAssignChecked, left, right, left.Type); 1544 } 1545 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssignChecked, "op_Addition", left, right, conversion, true); 1546 } 1547 return GetMethodBasedAssignOperator(ExpressionType.AddAssignChecked, left, right, method, conversion, true); 1548 } 1549 1550 1551 /// <summary> 1552 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking. 1553 /// </summary> 1554 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1555 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1556 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> 1557 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> AddChecked(Expression left, Expression right)1558 public static BinaryExpression AddChecked(Expression left, Expression right) { 1559 return AddChecked(left, right, null); 1560 } 1561 1562 /// <summary> 1563 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking. 1564 /// </summary> 1565 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1566 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1567 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1568 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> 1569 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1570 /// </returns> AddChecked(Expression left, Expression right, MethodInfo method)1571 public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) { 1572 RequiresCanRead(left, "left"); 1573 RequiresCanRead(right, "right"); 1574 if (method == null) { 1575 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1576 return new SimpleBinaryExpression(ExpressionType.AddChecked, left, right, left.Type); 1577 } 1578 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.AddChecked, "op_Addition", left, right, false); 1579 } 1580 return GetMethodBasedBinaryOperator(ExpressionType.AddChecked, left, right, method, true); 1581 } 1582 1583 1584 /// <summary> 1585 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking. 1586 /// </summary> 1587 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1588 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1589 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> 1590 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Subtract(Expression left, Expression right)1591 public static BinaryExpression Subtract(Expression left, Expression right) { 1592 return Subtract(left, right, null); 1593 } 1594 1595 /// <summary> 1596 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking. 1597 /// </summary> 1598 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1599 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1600 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1601 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> 1602 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1603 /// </returns> Subtract(Expression left, Expression right, MethodInfo method)1604 public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) { 1605 RequiresCanRead(left, "left"); 1606 RequiresCanRead(right, "right"); 1607 if (method == null) { 1608 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1609 return new SimpleBinaryExpression(ExpressionType.Subtract, left, right, left.Type); 1610 } 1611 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Subtract, "op_Subtraction", left, right, true); 1612 } 1613 return GetMethodBasedBinaryOperator(ExpressionType.Subtract, left, right, method, true); 1614 } 1615 1616 1617 /// <summary> 1618 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. 1619 /// </summary> 1620 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1621 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1622 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 1623 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> SubtractAssign(Expression left, Expression right)1624 public static BinaryExpression SubtractAssign(Expression left, Expression right) { 1625 return SubtractAssign(left, right, null, null); 1626 } 1627 1628 /// <summary> 1629 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. 1630 /// </summary> 1631 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1632 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1633 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1634 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 1635 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1636 /// </returns> SubtractAssign(Expression left, Expression right, MethodInfo method)1637 public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method) { 1638 return SubtractAssign(left, right, method, null); 1639 } 1640 1641 /// <summary> 1642 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. 1643 /// </summary> 1644 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1645 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1646 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1647 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1648 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 1649 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1650 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1651 /// </returns> SubtractAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1652 public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1653 RequiresCanRead(left, "left"); 1654 RequiresCanWrite(left, "left"); 1655 RequiresCanRead(right, "right"); 1656 if (method == null) { 1657 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1658 // conversion is not supported for binary ops on arithmetic types without operator overloading 1659 if (conversion != null) { 1660 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1661 } 1662 return new SimpleBinaryExpression(ExpressionType.SubtractAssign, left, right, left.Type); 1663 } 1664 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssign, "op_Subtraction", left, right, conversion, true); 1665 } 1666 return GetMethodBasedAssignOperator(ExpressionType.SubtractAssign, left, right, method, conversion, true); 1667 } 1668 1669 1670 /// <summary> 1671 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. 1672 /// </summary> 1673 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1674 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1675 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 1676 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> SubtractAssignChecked(Expression left, Expression right)1677 public static BinaryExpression SubtractAssignChecked(Expression left, Expression right) { 1678 return SubtractAssignChecked(left, right, null); 1679 } 1680 1681 /// <summary> 1682 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. 1683 /// </summary> 1684 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1685 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1686 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1687 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 1688 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1689 /// </returns> SubtractAssignChecked(Expression left, Expression right, MethodInfo method)1690 public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method) { 1691 return SubtractAssignChecked(left, right, method, null); 1692 } 1693 1694 /// <summary> 1695 /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. 1696 /// </summary> 1697 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1698 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1699 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1700 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1701 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 1702 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1703 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1704 /// </returns> SubtractAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1705 public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1706 RequiresCanRead(left, "left"); 1707 RequiresCanWrite(left, "left"); 1708 RequiresCanRead(right, "right"); 1709 if (method == null) { 1710 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1711 // conversion is not supported for binary ops on arithmetic types without operator overloading 1712 if (conversion != null) { 1713 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1714 } 1715 return new SimpleBinaryExpression(ExpressionType.SubtractAssignChecked, left, right, left.Type); 1716 } 1717 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssignChecked, "op_Subtraction", left, right, conversion, true); 1718 } 1719 return GetMethodBasedAssignOperator(ExpressionType.SubtractAssignChecked, left, right, method, conversion, true); 1720 } 1721 1722 1723 /// <summary> 1724 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking. 1725 /// </summary> 1726 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1727 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1728 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> 1729 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> SubtractChecked(Expression left, Expression right)1730 public static BinaryExpression SubtractChecked(Expression left, Expression right) { 1731 return SubtractChecked(left, right, null); 1732 } 1733 1734 /// <summary> 1735 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking. 1736 /// </summary> 1737 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1738 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1739 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1740 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> 1741 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1742 /// </returns> SubtractChecked(Expression left, Expression right, MethodInfo method)1743 public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) { 1744 RequiresCanRead(left, "left"); 1745 RequiresCanRead(right, "right"); 1746 if (method == null) { 1747 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1748 return new SimpleBinaryExpression(ExpressionType.SubtractChecked, left, right, left.Type); 1749 } 1750 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.SubtractChecked, "op_Subtraction", left, right, true); 1751 } 1752 return GetMethodBasedBinaryOperator(ExpressionType.SubtractChecked, left, right, method, true); 1753 } 1754 1755 1756 /// <summary> 1757 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation. 1758 /// </summary> 1759 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1760 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1761 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> 1762 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Divide(Expression left, Expression right)1763 public static BinaryExpression Divide(Expression left, Expression right) { 1764 return Divide(left, right, null); 1765 } 1766 1767 /// <summary> 1768 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation. 1769 /// </summary> 1770 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1771 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1772 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1773 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> 1774 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1775 /// </returns> Divide(Expression left, Expression right, MethodInfo method)1776 public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) { 1777 RequiresCanRead(left, "left"); 1778 RequiresCanRead(right, "right"); 1779 if (method == null) { 1780 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1781 return new SimpleBinaryExpression(ExpressionType.Divide, left, right, left.Type); 1782 } 1783 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Divide, "op_Division", left, right, true); 1784 } 1785 return GetMethodBasedBinaryOperator(ExpressionType.Divide, left, right, method, true); 1786 } 1787 1788 1789 /// <summary> 1790 /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. 1791 /// </summary> 1792 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1793 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1794 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 1795 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> DivideAssign(Expression left, Expression right)1796 public static BinaryExpression DivideAssign(Expression left, Expression right) { 1797 return DivideAssign(left, right, null, null); 1798 } 1799 1800 /// <summary> 1801 /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. 1802 /// </summary> 1803 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1804 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1805 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1806 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 1807 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1808 /// </returns> DivideAssign(Expression left, Expression right, MethodInfo method)1809 public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method) { 1810 return DivideAssign(left, right, method, null); 1811 } 1812 1813 /// <summary> 1814 /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. 1815 /// </summary> 1816 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1817 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1818 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1819 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1820 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 1821 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1822 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1823 /// </returns> DivideAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1824 public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1825 RequiresCanRead(left, "left"); 1826 RequiresCanWrite(left, "left"); 1827 RequiresCanRead(right, "right"); 1828 if (method == null) { 1829 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1830 // conversion is not supported for binary ops on arithmetic types without operator overloading 1831 if (conversion != null) { 1832 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1833 } 1834 return new SimpleBinaryExpression(ExpressionType.DivideAssign, left, right, left.Type); 1835 } 1836 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.DivideAssign, "op_Division", left, right, conversion, true); 1837 } 1838 return GetMethodBasedAssignOperator(ExpressionType.DivideAssign, left, right, method, conversion, true); 1839 } 1840 1841 1842 /// <summary> 1843 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation. 1844 /// </summary> 1845 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1846 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1847 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> 1848 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Modulo(Expression left, Expression right)1849 public static BinaryExpression Modulo(Expression left, Expression right) { 1850 return Modulo(left, right, null); 1851 } 1852 1853 /// <summary> 1854 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation. 1855 /// </summary> 1856 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1857 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1858 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1859 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> 1860 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1861 /// </returns> Modulo(Expression left, Expression right, MethodInfo method)1862 public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method) { 1863 RequiresCanRead(left, "left"); 1864 RequiresCanRead(right, "right"); 1865 if (method == null) { 1866 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1867 return new SimpleBinaryExpression(ExpressionType.Modulo, left, right, left.Type); 1868 } 1869 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Modulo, "op_Modulus", left, right, true); 1870 } 1871 return GetMethodBasedBinaryOperator(ExpressionType.Modulo, left, right, method, true); 1872 } 1873 1874 1875 /// <summary> 1876 /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. 1877 /// </summary> 1878 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1879 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1880 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 1881 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> ModuloAssign(Expression left, Expression right)1882 public static BinaryExpression ModuloAssign(Expression left, Expression right) { 1883 return ModuloAssign(left, right, null, null); 1884 } 1885 1886 /// <summary> 1887 /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. 1888 /// </summary> 1889 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1890 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1891 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1892 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 1893 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1894 /// </returns> ModuloAssign(Expression left, Expression right, MethodInfo method)1895 public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method) { 1896 return ModuloAssign(left, right, method, null); 1897 } 1898 1899 /// <summary> 1900 /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. 1901 /// </summary> 1902 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1903 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1904 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1905 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1906 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 1907 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1908 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1909 /// </returns> ModuloAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1910 public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1911 RequiresCanRead(left, "left"); 1912 RequiresCanWrite(left, "left"); 1913 RequiresCanRead(right, "right"); 1914 if (method == null) { 1915 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1916 // conversion is not supported for binary ops on arithmetic types without operator overloading 1917 if (conversion != null) { 1918 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 1919 } 1920 return new SimpleBinaryExpression(ExpressionType.ModuloAssign, left, right, left.Type); 1921 } 1922 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ModuloAssign, "op_Modulus", left, right, conversion, true); 1923 } 1924 return GetMethodBasedAssignOperator(ExpressionType.ModuloAssign, left, right, method, conversion, true); 1925 } 1926 1927 1928 /// <summary> 1929 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking. 1930 /// </summary> 1931 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1932 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1933 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> 1934 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Multiply(Expression left, Expression right)1935 public static BinaryExpression Multiply(Expression left, Expression right) { 1936 return Multiply(left, right, null); 1937 } 1938 1939 /// <summary> 1940 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking. 1941 /// </summary> 1942 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1943 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1944 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1945 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> 1946 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1947 /// </returns> Multiply(Expression left, Expression right, MethodInfo method)1948 public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) { 1949 RequiresCanRead(left, "left"); 1950 RequiresCanRead(right, "right"); 1951 if (method == null) { 1952 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 1953 return new SimpleBinaryExpression(ExpressionType.Multiply, left, right, left.Type); 1954 } 1955 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Multiply, "op_Multiply", left, right, true); 1956 } 1957 return GetMethodBasedBinaryOperator(ExpressionType.Multiply, left, right, method, true); 1958 } 1959 1960 1961 /// <summary> 1962 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. 1963 /// </summary> 1964 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1965 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1966 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 1967 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> MultiplyAssign(Expression left, Expression right)1968 public static BinaryExpression MultiplyAssign(Expression left, Expression right) { 1969 return MultiplyAssign(left, right, null, null); 1970 } 1971 1972 /// <summary> 1973 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. 1974 /// </summary> 1975 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1976 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1977 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1978 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 1979 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 1980 /// </returns> MultiplyAssign(Expression left, Expression right, MethodInfo method)1981 public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method) { 1982 return MultiplyAssign(left, right, method, null); 1983 } 1984 1985 /// <summary> 1986 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. 1987 /// </summary> 1988 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 1989 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 1990 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 1991 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 1992 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 1993 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 1994 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 1995 /// </returns> MultiplyAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)1996 public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 1997 RequiresCanRead(left, "left"); 1998 RequiresCanWrite(left, "left"); 1999 RequiresCanRead(right, "right"); 2000 if (method == null) { 2001 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 2002 // conversion is not supported for binary ops on arithmetic types without operator overloading 2003 if (conversion != null) { 2004 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2005 } 2006 return new SimpleBinaryExpression(ExpressionType.MultiplyAssign, left, right, left.Type); 2007 } 2008 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssign, "op_Multiply", left, right, conversion, true); 2009 } 2010 return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssign, left, right, method, conversion, true); 2011 } 2012 2013 2014 /// <summary> 2015 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. 2016 /// </summary> 2017 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2018 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2019 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 2020 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> MultiplyAssignChecked(Expression left, Expression right)2021 public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right) { 2022 return MultiplyAssignChecked(left, right, null); 2023 } 2024 2025 /// <summary> 2026 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. 2027 /// </summary> 2028 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2029 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2030 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2031 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 2032 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2033 /// </returns> MultiplyAssignChecked(Expression left, Expression right, MethodInfo method)2034 public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method) { 2035 return MultiplyAssignChecked(left, right, method, null); 2036 } 2037 2038 /// <summary> 2039 /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. 2040 /// </summary> 2041 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2042 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2043 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2044 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2045 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 2046 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2047 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2048 /// </returns> MultiplyAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2049 public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2050 RequiresCanRead(left, "left"); 2051 RequiresCanWrite(left, "left"); 2052 RequiresCanRead(right, "right"); 2053 if (method == null) { 2054 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 2055 // conversion is not supported for binary ops on arithmetic types without operator overloading 2056 if (conversion != null) { 2057 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2058 } 2059 return new SimpleBinaryExpression(ExpressionType.MultiplyAssignChecked, left, right, left.Type); 2060 } 2061 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssignChecked, "op_Multiply", left, right, conversion, true); 2062 } 2063 return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssignChecked, left, right, method, conversion, true); 2064 } 2065 2066 2067 /// <summary> 2068 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking. 2069 /// </summary> 2070 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2071 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2072 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> 2073 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> MultiplyChecked(Expression left, Expression right)2074 public static BinaryExpression MultiplyChecked(Expression left, Expression right) { 2075 return MultiplyChecked(left, right, null); 2076 } 2077 2078 /// <summary> 2079 /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking. 2080 /// </summary> 2081 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2082 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2083 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2084 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> 2085 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2086 /// </returns> MultiplyChecked(Expression left, Expression right, MethodInfo method)2087 public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) { 2088 RequiresCanRead(left, "left"); 2089 RequiresCanRead(right, "right"); 2090 if (method == null) { 2091 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) { 2092 return new SimpleBinaryExpression(ExpressionType.MultiplyChecked, left, right, left.Type); 2093 } 2094 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.MultiplyChecked, "op_Multiply", left, right, true); 2095 } 2096 return GetMethodBasedBinaryOperator(ExpressionType.MultiplyChecked, left, right, method, true); 2097 } 2098 IsSimpleShift(Type left, Type right)2099 private static bool IsSimpleShift(Type left, Type right) { 2100 return TypeUtils.IsInteger(left) 2101 && TypeUtils.GetNonNullableType(right) == typeof(int); 2102 } 2103 GetResultTypeOfShift(Type left, Type right)2104 private static Type GetResultTypeOfShift(Type left, Type right) { 2105 if (!left.IsNullableType() && right.IsNullableType()) { 2106 // lift the result type to Nullable<T> 2107 return typeof(Nullable<>).MakeGenericType(left); 2108 } 2109 return left; 2110 } 2111 2112 2113 /// <summary> 2114 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation. 2115 /// </summary> 2116 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2117 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2118 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> 2119 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> LeftShift(Expression left, Expression right)2120 public static BinaryExpression LeftShift(Expression left, Expression right) { 2121 return LeftShift(left, right, null); 2122 } 2123 2124 /// <summary> 2125 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation. 2126 /// </summary> 2127 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2128 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2129 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2130 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> 2131 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2132 /// </returns> LeftShift(Expression left, Expression right, MethodInfo method)2133 public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) { 2134 RequiresCanRead(left, "left"); 2135 RequiresCanRead(right, "right"); 2136 if (method == null) { 2137 if (IsSimpleShift(left.Type, right.Type)) { 2138 Type resultType = GetResultTypeOfShift(left.Type, right.Type); 2139 return new SimpleBinaryExpression(ExpressionType.LeftShift, left, right, resultType); 2140 } 2141 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.LeftShift, "op_LeftShift", left, right, true); 2142 } 2143 return GetMethodBasedBinaryOperator(ExpressionType.LeftShift, left, right, method, true); 2144 } 2145 2146 2147 /// <summary> 2148 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. 2149 /// </summary> 2150 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2151 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2152 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 2153 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> LeftShiftAssign(Expression left, Expression right)2154 public static BinaryExpression LeftShiftAssign(Expression left, Expression right) { 2155 return LeftShiftAssign(left, right, null, null); 2156 } 2157 2158 /// <summary> 2159 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. 2160 /// </summary> 2161 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2162 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2163 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2164 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 2165 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2166 /// </returns> LeftShiftAssign(Expression left, Expression right, MethodInfo method)2167 public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method) { 2168 return LeftShiftAssign(left, right, method, null); 2169 } 2170 2171 /// <summary> 2172 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. 2173 /// </summary> 2174 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2175 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2176 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2177 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2178 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 2179 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2180 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2181 /// </returns> LeftShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2182 public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2183 RequiresCanRead(left, "left"); 2184 RequiresCanWrite(left, "left"); 2185 RequiresCanRead(right, "right"); 2186 if (method == null) { 2187 if (IsSimpleShift(left.Type, right.Type)) { 2188 // conversion is not supported for binary ops on arithmetic types without operator overloading 2189 if (conversion != null) { 2190 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2191 } 2192 Type resultType = GetResultTypeOfShift(left.Type, right.Type); 2193 return new SimpleBinaryExpression(ExpressionType.LeftShiftAssign, left, right, resultType); 2194 } 2195 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.LeftShiftAssign, "op_LeftShift", left, right, conversion, true); 2196 } 2197 return GetMethodBasedAssignOperator(ExpressionType.LeftShiftAssign, left, right, method, conversion, true); 2198 } 2199 2200 2201 /// <summary> 2202 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation. 2203 /// </summary> 2204 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2205 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2206 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> 2207 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> RightShift(Expression left, Expression right)2208 public static BinaryExpression RightShift(Expression left, Expression right) { 2209 return RightShift(left, right, null); 2210 } 2211 2212 /// <summary> 2213 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation. 2214 /// </summary> 2215 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2216 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2217 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2218 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> 2219 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2220 /// </returns> RightShift(Expression left, Expression right, MethodInfo method)2221 public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) { 2222 RequiresCanRead(left, "left"); 2223 RequiresCanRead(right, "right"); 2224 if (method == null) { 2225 if (IsSimpleShift(left.Type, right.Type)) { 2226 Type resultType = GetResultTypeOfShift(left.Type, right.Type); 2227 return new SimpleBinaryExpression(ExpressionType.RightShift, left, right, resultType); 2228 } 2229 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.RightShift, "op_RightShift", left, right, true); 2230 } 2231 return GetMethodBasedBinaryOperator(ExpressionType.RightShift, left, right, method, true); 2232 } 2233 2234 2235 /// <summary> 2236 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. 2237 /// </summary> 2238 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2239 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2240 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 2241 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> RightShiftAssign(Expression left, Expression right)2242 public static BinaryExpression RightShiftAssign(Expression left, Expression right) { 2243 return RightShiftAssign(left, right, null, null); 2244 } 2245 2246 /// <summary> 2247 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. 2248 /// </summary> 2249 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2250 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2251 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2252 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 2253 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2254 /// </returns> RightShiftAssign(Expression left, Expression right, MethodInfo method)2255 public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method) { 2256 return RightShiftAssign(left, right, method, null); 2257 } 2258 2259 /// <summary> 2260 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. 2261 /// </summary> 2262 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2263 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2264 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2265 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2266 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 2267 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2268 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2269 /// </returns> RightShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2270 public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2271 RequiresCanRead(left, "left"); 2272 RequiresCanWrite(left, "left"); 2273 RequiresCanRead(right, "right"); 2274 if (method == null) { 2275 if (IsSimpleShift(left.Type, right.Type)) { 2276 // conversion is not supported for binary ops on arithmetic types without operator overloading 2277 if (conversion != null) { 2278 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2279 } 2280 Type resultType = GetResultTypeOfShift(left.Type, right.Type); 2281 return new SimpleBinaryExpression(ExpressionType.RightShiftAssign, left, right, resultType); 2282 } 2283 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.RightShiftAssign, "op_RightShift", left, right, conversion, true); 2284 } 2285 return GetMethodBasedAssignOperator(ExpressionType.RightShiftAssign, left, right, method, conversion, true); 2286 } 2287 2288 2289 /// <summary> 2290 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation. 2291 /// </summary> 2292 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2293 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2294 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> 2295 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> And(Expression left, Expression right)2296 public static BinaryExpression And(Expression left, Expression right) { 2297 return And(left, right, null); 2298 } 2299 2300 /// <summary> 2301 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation. 2302 /// </summary> 2303 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2304 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2305 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2306 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> 2307 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2308 /// </returns> And(Expression left, Expression right, MethodInfo method)2309 public static BinaryExpression And(Expression left, Expression right, MethodInfo method) { 2310 RequiresCanRead(left, "left"); 2311 RequiresCanRead(right, "right"); 2312 if (method == null) { 2313 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2314 return new SimpleBinaryExpression(ExpressionType.And, left, right, left.Type); 2315 } 2316 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.And, "op_BitwiseAnd", left, right, true); 2317 } 2318 return GetMethodBasedBinaryOperator(ExpressionType.And, left, right, method, true); 2319 } 2320 2321 2322 /// <summary> 2323 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. 2324 /// </summary> 2325 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2326 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2327 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 2328 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> AndAssign(Expression left, Expression right)2329 public static BinaryExpression AndAssign(Expression left, Expression right) { 2330 return AndAssign(left, right, null, null); 2331 } 2332 2333 /// <summary> 2334 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. 2335 /// </summary> 2336 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2337 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2338 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2339 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 2340 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2341 /// </returns> AndAssign(Expression left, Expression right, MethodInfo method)2342 public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method) { 2343 return AndAssign(left, right, method, null); 2344 } 2345 2346 /// <summary> 2347 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. 2348 /// </summary> 2349 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2350 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2351 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2352 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2353 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 2354 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2355 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2356 /// </returns> AndAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2357 public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2358 RequiresCanRead(left, "left"); 2359 RequiresCanWrite(left, "left"); 2360 RequiresCanRead(right, "right"); 2361 if (method == null) { 2362 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2363 // conversion is not supported for binary ops on arithmetic types without operator overloading 2364 if (conversion != null) { 2365 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2366 } 2367 return new SimpleBinaryExpression(ExpressionType.AndAssign, left, right, left.Type); 2368 } 2369 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AndAssign, "op_BitwiseAnd", left, right, conversion, true); 2370 } 2371 return GetMethodBasedAssignOperator(ExpressionType.AndAssign, left, right, method, conversion, true); 2372 } 2373 2374 2375 /// <summary> 2376 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation. 2377 /// </summary> 2378 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2379 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2380 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> 2381 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Or(Expression left, Expression right)2382 public static BinaryExpression Or(Expression left, Expression right) { 2383 return Or(left, right, null); 2384 } 2385 2386 /// <summary> 2387 /// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation. 2388 /// </summary> 2389 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2390 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2391 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2392 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> 2393 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2394 /// </returns> Or(Expression left, Expression right, MethodInfo method)2395 public static BinaryExpression Or(Expression left, Expression right, MethodInfo method) { 2396 RequiresCanRead(left, "left"); 2397 RequiresCanRead(right, "right"); 2398 if (method == null) { 2399 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2400 return new SimpleBinaryExpression(ExpressionType.Or, left, right, left.Type); 2401 } 2402 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Or, "op_BitwiseOr", left, right, true); 2403 } 2404 return GetMethodBasedBinaryOperator(ExpressionType.Or, left, right, method, true); 2405 } 2406 2407 2408 /// <summary> 2409 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. 2410 /// </summary> 2411 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2412 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2413 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 2414 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> OrAssign(Expression left, Expression right)2415 public static BinaryExpression OrAssign(Expression left, Expression right) { 2416 return OrAssign(left, right, null, null); 2417 } 2418 2419 /// <summary> 2420 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. 2421 /// </summary> 2422 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2423 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2424 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2425 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 2426 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2427 /// </returns> OrAssign(Expression left, Expression right, MethodInfo method)2428 public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method) { 2429 return OrAssign(left, right, method, null); 2430 } 2431 2432 /// <summary> 2433 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. 2434 /// </summary> 2435 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2436 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2437 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2438 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2439 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 2440 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2441 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2442 /// </returns> OrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2443 public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2444 RequiresCanRead(left, "left"); 2445 RequiresCanWrite(left, "left"); 2446 RequiresCanRead(right, "right"); 2447 if (method == null) { 2448 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2449 // conversion is not supported for binary ops on arithmetic types without operator overloading 2450 if (conversion != null) { 2451 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2452 } 2453 return new SimpleBinaryExpression(ExpressionType.OrAssign, left, right, left.Type); 2454 } 2455 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.OrAssign, "op_BitwiseOr", left, right, conversion, true); 2456 } 2457 return GetMethodBasedAssignOperator(ExpressionType.OrAssign, left, right, method, conversion, true); 2458 } 2459 2460 /// <summary> 2461 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types. 2462 /// </summary> 2463 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2464 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2465 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> 2466 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> ExclusiveOr(Expression left, Expression right)2467 public static BinaryExpression ExclusiveOr(Expression left, Expression right) { 2468 return ExclusiveOr(left, right, null); 2469 } 2470 2471 /// <summary> 2472 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types. 2473 /// </summary> 2474 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2475 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2476 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2477 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> 2478 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2479 /// </returns> ExclusiveOr(Expression left, Expression right, MethodInfo method)2480 public static BinaryExpression ExclusiveOr(Expression left, Expression right, MethodInfo method) { 2481 RequiresCanRead(left, "left"); 2482 RequiresCanRead(right, "right"); 2483 if (method == null) { 2484 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2485 return new SimpleBinaryExpression(ExpressionType.ExclusiveOr, left, right, left.Type); 2486 } 2487 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.ExclusiveOr, "op_ExclusiveOr", left, right, true); 2488 } 2489 return GetMethodBasedBinaryOperator(ExpressionType.ExclusiveOr, left, right, method, true); 2490 } 2491 2492 /// <summary> 2493 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. 2494 /// </summary> 2495 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2496 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2497 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 2498 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> ExclusiveOrAssign(Expression left, Expression right)2499 public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right) { 2500 return ExclusiveOrAssign(left, right, null, null); 2501 } 2502 2503 /// <summary> 2504 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. 2505 /// </summary> 2506 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2507 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2508 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2509 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 2510 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2511 /// </returns> ExclusiveOrAssign(Expression left, Expression right, MethodInfo method)2512 public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method) { 2513 return ExclusiveOrAssign(left, right, method, null); 2514 } 2515 2516 /// <summary> 2517 /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. 2518 /// </summary> 2519 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2520 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2521 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2522 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2523 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 2524 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2525 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2526 /// </returns> ExclusiveOrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2527 public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2528 RequiresCanRead(left, "left"); 2529 RequiresCanWrite(left, "left"); 2530 RequiresCanRead(right, "right"); 2531 if (method == null) { 2532 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) { 2533 // conversion is not supported for binary ops on arithmetic types without operator overloading 2534 if (conversion != null) { 2535 throw Error.ConversionIsNotSupportedForArithmeticTypes(); 2536 } 2537 return new SimpleBinaryExpression(ExpressionType.ExclusiveOrAssign, left, right, left.Type); 2538 } 2539 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ExclusiveOrAssign, "op_ExclusiveOr", left, right, conversion, true); 2540 } 2541 return GetMethodBasedAssignOperator(ExpressionType.ExclusiveOrAssign, left, right, method, conversion, true); 2542 } 2543 2544 /// <summary> 2545 /// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power. 2546 /// </summary> 2547 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2548 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2549 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> 2550 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> Power(Expression left, Expression right)2551 public static BinaryExpression Power(Expression left, Expression right) { 2552 return Power(left, right, null); 2553 } 2554 2555 /// <summary> 2556 /// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power. 2557 /// </summary> 2558 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2559 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2560 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2561 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> 2562 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2563 /// </returns> Power(Expression left, Expression right, MethodInfo method)2564 public static BinaryExpression Power(Expression left, Expression right, MethodInfo method) { 2565 RequiresCanRead(left, "left"); 2566 RequiresCanRead(right, "right"); 2567 if (method == null) { 2568 Type mathType = typeof(System.Math); 2569 method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public); 2570 if (method == null) { 2571 throw Error.BinaryOperatorNotDefined(ExpressionType.Power, left.Type, right.Type); 2572 } 2573 } 2574 return GetMethodBasedBinaryOperator(ExpressionType.Power, left, right, method, true); 2575 } 2576 2577 2578 /// <summary> 2579 /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. 2580 /// </summary> 2581 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2582 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2583 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 2584 /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> PowerAssign(Expression left, Expression right)2585 public static BinaryExpression PowerAssign(Expression left, Expression right) { 2586 return PowerAssign(left, right, null, null); 2587 } 2588 2589 /// <summary> 2590 /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. 2591 /// </summary> 2592 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2593 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2594 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2595 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 2596 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. 2597 /// </returns> PowerAssign(Expression left, Expression right, MethodInfo method)2598 public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method) { 2599 return PowerAssign(left, right, method, null); 2600 } 2601 2602 /// <summary> 2603 /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. 2604 /// </summary> 2605 /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> 2606 /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> 2607 /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> 2608 /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> 2609 /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 2610 /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, 2611 /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. 2612 /// </returns> PowerAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion)2613 public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) { 2614 RequiresCanRead(left, "left"); 2615 RequiresCanWrite(left, "left"); 2616 RequiresCanRead(right, "right"); 2617 if (method == null) { 2618 Type mathType = typeof(System.Math); 2619 method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public); 2620 if (method == null) { 2621 throw Error.BinaryOperatorNotDefined(ExpressionType.PowerAssign, left.Type, right.Type); 2622 } 2623 } 2624 return GetMethodBasedAssignOperator(ExpressionType.PowerAssign, left, right, method, conversion, true); 2625 } 2626 2627 #endregion 2628 2629 #region ArrayIndex Expression 2630 2631 2632 /// <summary> 2633 /// Creates a BinaryExpression that represents applying an array index operator to an array of rank one. 2634 /// </summary> 2635 /// <param name="array">An Expression to set the Left property equal to.</param> 2636 /// <param name="index">An Expression to set the Right property equal to.</param> 2637 /// <returns>A BinaryExpression that has the NodeType property equal to ArrayIndex and the Left and Right properties set to the specified values.</returns> ArrayIndex(Expression array, Expression index)2638 public static BinaryExpression ArrayIndex(Expression array, Expression index) { 2639 RequiresCanRead(array, "array"); 2640 RequiresCanRead(index, "index"); 2641 if (index.Type != typeof(int)) { 2642 throw Error.ArgumentMustBeArrayIndexType(); 2643 } 2644 2645 Type arrayType = array.Type; 2646 if (!arrayType.IsArray) { 2647 throw Error.ArgumentMustBeArray(); 2648 } 2649 if (arrayType.GetArrayRank() != 1) { 2650 throw Error.IncorrectNumberOfIndexes(); 2651 } 2652 2653 return new SimpleBinaryExpression(ExpressionType.ArrayIndex, array, index, arrayType.GetElementType()); 2654 } 2655 2656 #endregion 2657 } 2658 } 2659