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