You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3005 lines
171 KiB
3005 lines
171 KiB
#if NET20 || NET30 || !NET_4_6 |
|
|
|
// Copyright (c) Microsoft. All rights reserved. |
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information. |
|
|
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Reflection; |
|
using LinqInternal.Core; |
|
|
|
namespace System.Linq.Expressions.Reimplement |
|
{ |
|
/// <summary> |
|
/// Represents an expression that has a binary operator. |
|
/// </summary> |
|
[DebuggerTypeProxy(typeof(BinaryExpressionProxy))] |
|
public class BinaryExpression : Expression |
|
{ |
|
private readonly Expression _left; |
|
private readonly Expression _right; |
|
|
|
internal BinaryExpression(Expression left, Expression right) |
|
{ |
|
_left = left; |
|
_right = right; |
|
} |
|
|
|
/// <summary> |
|
/// Gets a value that indicates whether the expression tree node can be reduced. |
|
/// </summary> |
|
public override bool CanReduce |
|
{ |
|
get |
|
{ |
|
// Only OpAssignments are reducible. |
|
return IsOpAssignment(NodeType); |
|
} |
|
} |
|
|
|
private static bool IsOpAssignment(ExpressionType op) |
|
{ |
|
switch (op) |
|
{ |
|
case ExpressionType.AddAssign: |
|
case ExpressionType.SubtractAssign: |
|
case ExpressionType.MultiplyAssign: |
|
case ExpressionType.AddAssignChecked: |
|
case ExpressionType.SubtractAssignChecked: |
|
case ExpressionType.MultiplyAssignChecked: |
|
case ExpressionType.DivideAssign: |
|
case ExpressionType.ModuloAssign: |
|
case ExpressionType.PowerAssign: |
|
case ExpressionType.AndAssign: |
|
case ExpressionType.OrAssign: |
|
case ExpressionType.RightShiftAssign: |
|
case ExpressionType.LeftShiftAssign: |
|
case ExpressionType.ExclusiveOrAssign: |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Gets the right operand of the binary operation. |
|
/// </summary> |
|
public Expression Right |
|
{ |
|
get { return _right; } |
|
} |
|
|
|
/// <summary> |
|
/// Gets the left operand of the binary operation. |
|
/// </summary> |
|
public Expression Left |
|
{ |
|
get { return _left; } |
|
} |
|
|
|
/// <summary> |
|
/// Gets the implementing method for the binary operation. |
|
/// </summary> |
|
public MethodInfo Method |
|
{ |
|
get { return GetMethod(); } |
|
} |
|
|
|
internal virtual MethodInfo GetMethod() |
|
{ |
|
return null; |
|
} |
|
|
|
// Note: takes children in evaluation order, which is also the order |
|
// that ExpressionVisitor visits them. Having them this way reduces the |
|
// chances people will make a mistake and use an inconsistent order in |
|
// derived visitors. |
|
|
|
/// <summary> |
|
/// Creates a new expression that is like this one, but using the |
|
/// supplied children. If all of the children are the same, it will |
|
/// return this expression. |
|
/// </summary> |
|
/// <param name="left">The <see cref="Left" /> property of the result.</param> |
|
/// <param name="conversion">The <see cref="Conversion" /> property of the result.</param> |
|
/// <param name="right">The <see cref="Right" /> property of the result.</param> |
|
/// <returns>This expression if no children changed, or an expression with the updated children.</returns> |
|
public BinaryExpression Update(Expression left, LambdaExpression conversion, Expression right) |
|
{ |
|
if (left == Left && right == Right && conversion == Conversion) |
|
{ |
|
return this; |
|
} |
|
if (IsReferenceComparison) |
|
{ |
|
if (NodeType == ExpressionType.Equal) |
|
{ |
|
return ReferenceEqual(left, right); |
|
} |
|
else |
|
{ |
|
return ReferenceNotEqual(left, right); |
|
} |
|
} |
|
return MakeBinary(NodeType, left, right, IsLiftedToNull, Method, conversion); |
|
} |
|
|
|
/// <summary> |
|
/// Reduces the binary expression node to a simpler expression. |
|
/// If CanReduce returns true, this should return a valid expression. |
|
/// This method is allowed to return another node which itself |
|
/// must be reduced. |
|
/// </summary> |
|
/// <returns>The reduced expression.</returns> |
|
public override Expression Reduce() |
|
{ |
|
// Only reduce OpAssignment expressions. |
|
if (IsOpAssignment(NodeType)) |
|
{ |
|
switch (_left.NodeType) |
|
{ |
|
case ExpressionType.MemberAccess: |
|
return ReduceMember(); |
|
|
|
case ExpressionType.Index: |
|
return ReduceIndex(); |
|
|
|
default: |
|
return ReduceVariable(); |
|
} |
|
} |
|
return this; |
|
} |
|
|
|
// Return the corresponding Op of an assignment op. |
|
private static ExpressionType GetBinaryOpFromAssignmentOp(ExpressionType op) |
|
{ |
|
Debug.Assert(IsOpAssignment(op)); |
|
switch (op) |
|
{ |
|
case ExpressionType.AddAssign: |
|
return ExpressionType.Add; |
|
|
|
case ExpressionType.AddAssignChecked: |
|
return ExpressionType.AddChecked; |
|
|
|
case ExpressionType.SubtractAssign: |
|
return ExpressionType.Subtract; |
|
|
|
case ExpressionType.SubtractAssignChecked: |
|
return ExpressionType.SubtractChecked; |
|
|
|
case ExpressionType.MultiplyAssign: |
|
return ExpressionType.Multiply; |
|
|
|
case ExpressionType.MultiplyAssignChecked: |
|
return ExpressionType.MultiplyChecked; |
|
|
|
case ExpressionType.DivideAssign: |
|
return ExpressionType.Divide; |
|
|
|
case ExpressionType.ModuloAssign: |
|
return ExpressionType.Modulo; |
|
|
|
case ExpressionType.PowerAssign: |
|
return ExpressionType.Power; |
|
|
|
case ExpressionType.AndAssign: |
|
return ExpressionType.And; |
|
|
|
case ExpressionType.OrAssign: |
|
return ExpressionType.Or; |
|
|
|
case ExpressionType.RightShiftAssign: |
|
return ExpressionType.RightShift; |
|
|
|
case ExpressionType.LeftShiftAssign: |
|
return ExpressionType.LeftShift; |
|
|
|
case ExpressionType.ExclusiveOrAssign: |
|
return ExpressionType.ExclusiveOr; |
|
|
|
default: |
|
// must be an error |
|
throw Error.InvalidOperation("op"); |
|
} |
|
} |
|
|
|
private Expression ReduceVariable() |
|
{ |
|
// v (op)= r |
|
// ... is reduced into ... |
|
// v = v (op) r |
|
var op = GetBinaryOpFromAssignmentOp(NodeType); |
|
Expression r = MakeBinary(op, _left, _right, false, Method); |
|
var conversion = GetConversion(); |
|
if (conversion != null) |
|
{ |
|
r = Invoke(conversion, r); |
|
} |
|
return Assign(_left, r); |
|
} |
|
|
|
private Expression ReduceMember() |
|
{ |
|
var member = (MemberExpression)_left; |
|
|
|
if (member.Expression == null) |
|
{ |
|
// static member, reduce the same as variable |
|
return ReduceVariable(); |
|
} |
|
else |
|
{ |
|
// left.b (op)= r |
|
// ... is reduced into ... |
|
// temp1 = left |
|
// temp2 = temp1.b (op) r |
|
// temp1.b = temp2 |
|
// temp2 |
|
var temp1 = Variable(member.Expression.Type, "temp1"); |
|
|
|
// 1. temp1 = left |
|
Expression e1 = Assign(temp1, member.Expression); |
|
|
|
// 2. temp2 = temp1.b (op) r |
|
var op = GetBinaryOpFromAssignmentOp(NodeType); |
|
Expression e2 = MakeBinary(op, MakeMemberAccess(temp1, member.Member), _right, false, Method); |
|
var conversion = GetConversion(); |
|
if (conversion != null) |
|
{ |
|
e2 = Invoke(conversion, e2); |
|
} |
|
var temp2 = Variable(e2.Type, "temp2"); |
|
e2 = Assign(temp2, e2); |
|
|
|
// 3. temp1.b = temp2 |
|
Expression e3 = Assign(MakeMemberAccess(temp1, member.Member), temp2); |
|
|
|
// 3. temp2 |
|
Expression e4 = temp2; |
|
|
|
return Block( |
|
new[] { temp1, temp2 }, |
|
e1, e2, e3, e4 |
|
); |
|
} |
|
} |
|
|
|
private Expression ReduceIndex() |
|
{ |
|
// left[a0, a1, ... aN] (op)= r |
|
// |
|
// ... is reduced into ... |
|
// |
|
// tempObj = left |
|
// tempArg0 = a0 |
|
// ... |
|
// tempArgN = aN |
|
// tempValue = tempObj[tempArg0, ... tempArgN] (op) r |
|
// tempObj[tempArg0, ... tempArgN] = tempValue |
|
|
|
var index = (IndexExpression)_left; |
|
|
|
var vars = new List<ParameterExpression>(index.Arguments.Count + 2); |
|
var exprs = new List<Expression>(index.Arguments.Count + 3); |
|
|
|
var tempObj = Variable(index.Object.Type, "tempObj"); |
|
vars.Add(tempObj); |
|
exprs.Add(Assign(tempObj, index.Object)); |
|
|
|
var tempArgs = new List<Expression>(index.Arguments.Count); |
|
foreach (var arg in index.Arguments) |
|
{ |
|
var tempArg = Variable(arg.Type, "tempArg" + tempArgs.Count); |
|
vars.Add(tempArg); |
|
tempArgs.Add(tempArg); |
|
exprs.Add(Assign(tempArg, arg)); |
|
} |
|
|
|
var tempIndex = MakeIndex(tempObj, index.Indexer, tempArgs); |
|
|
|
// tempValue = tempObj[tempArg0, ... tempArgN] (op) r |
|
var binaryOp = GetBinaryOpFromAssignmentOp(NodeType); |
|
Expression op = MakeBinary(binaryOp, tempIndex, _right, false, Method); |
|
var conversion = GetConversion(); |
|
if (conversion != null) |
|
{ |
|
op = Invoke(conversion, op); |
|
} |
|
var tempValue = Variable(op.Type, "tempValue"); |
|
vars.Add(tempValue); |
|
exprs.Add(Assign(tempValue, op)); |
|
|
|
// tempObj[tempArg0, ... tempArgN] = tempValue |
|
exprs.Add(Assign(tempIndex, tempValue)); |
|
|
|
return Block(vars, exprs); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the type conversion function that is used by a coalescing or compound assignment operation. |
|
/// </summary> |
|
public LambdaExpression Conversion |
|
{ |
|
get { return GetConversion(); } |
|
} |
|
|
|
internal virtual LambdaExpression GetConversion() |
|
{ |
|
return null; |
|
} |
|
|
|
/// <summary> |
|
/// Gets a value that indicates whether the expression tree node represents a lifted call to an operator. |
|
/// </summary> |
|
public bool IsLifted |
|
{ |
|
get |
|
{ |
|
if (NodeType == ExpressionType.Coalesce || NodeType == ExpressionType.Assign) |
|
{ |
|
return false; |
|
} |
|
if (_left.Type.IsNullableType()) |
|
{ |
|
var method = GetMethod(); |
|
return method == null || method.GetParameters()[0].ParameterType.GetNonRefType() != _left.Type; |
|
} |
|
return false; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 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. |
|
/// </summary> |
|
public bool IsLiftedToNull |
|
{ |
|
get { return IsLifted && Type.IsNullableType(); } |
|
} |
|
|
|
protected internal override Expression Accept(ExpressionVisitor visitor) |
|
{ |
|
return visitor.VisitBinary(this); |
|
} |
|
|
|
internal static Expression Create(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
if (nodeType == ExpressionType.Assign) |
|
{ |
|
Debug.Assert(method == null && type == left.Type); |
|
return new AssignBinaryExpression(left, right); |
|
} |
|
if (conversion != null) |
|
{ |
|
Debug.Assert(method == null && type == right.Type && nodeType == ExpressionType.Coalesce); |
|
return new CoalesceConversionBinaryExpression(left, right, conversion); |
|
} |
|
if (method != null) |
|
{ |
|
return new MethodBinaryExpression(nodeType, left, right, type, method); |
|
} |
|
if (type == typeof(bool)) |
|
{ |
|
return new LogicalBinaryExpression(nodeType, left, right); |
|
} |
|
return new SimpleBinaryExpression(nodeType, left, right, type); |
|
} |
|
|
|
internal bool IsLiftedLogical |
|
{ |
|
get |
|
{ |
|
var left = _left.Type; |
|
var right = _right.Type; |
|
var method = GetMethod(); |
|
var kind = NodeType; |
|
|
|
return |
|
(kind == ExpressionType.AndAlso || kind == ExpressionType.OrElse) && |
|
right == left && |
|
left.IsNullableType() && |
|
method != null && |
|
method.ReturnType == left.GetNonNullableType(); |
|
} |
|
} |
|
|
|
internal bool IsReferenceComparison |
|
{ |
|
get |
|
{ |
|
var left = _left.Type; |
|
var right = _right.Type; |
|
var method = GetMethod(); |
|
var kind = NodeType; |
|
|
|
return (kind == ExpressionType.Equal || kind == ExpressionType.NotEqual) && |
|
method == null && !left.IsValueType && !right.IsValueType; |
|
} |
|
} |
|
|
|
// |
|
// For a userdefined type T which has op_False defined and L, R are |
|
// nullable, (L AndAlso R) is computed as: |
|
// |
|
// L.HasValue |
|
// ? T.op_False(L.GetValueOrDefault()) |
|
// ? L |
|
// : R.HasValue |
|
// ? (T?)(T.op_BitwiseAnd(L.GetValueOrDefault(), R.GetValueOrDefault())) |
|
// : null |
|
// : null |
|
// |
|
// For a userdefined type T which has op_True defined and L, R are |
|
// nullable, (L OrElse R) is computed as: |
|
// |
|
// L.HasValue |
|
// ? T.op_True(L.GetValueOrDefault()) |
|
// ? L |
|
// : R.HasValue |
|
// ? (T?)(T.op_BitwiseOr(L.GetValueOrDefault(), R.GetValueOrDefault())) |
|
// : null |
|
// : null |
|
// |
|
// |
|
// This is the same behavior as VB. If you think about it, it makes |
|
// sense: it's combining the normal pattern for short-circuiting |
|
// operators, with the normal pattern for lifted operations: if either |
|
// of the operands is null, the result is also null. |
|
// |
|
internal Expression ReduceUserdefinedLifted() |
|
{ |
|
Debug.Assert(IsLiftedLogical); |
|
|
|
var left = Parameter(_left.Type, "left"); |
|
var right = Parameter(Right.Type, "right"); |
|
var opName = NodeType == ExpressionType.AndAlso ? "op_False" : "op_True"; |
|
var opTrueFalse = TypeHelper.GetBooleanOperator(Method.DeclaringType, opName); |
|
Debug.Assert(opTrueFalse != null); |
|
|
|
return Block( |
|
new[] { left }, |
|
Assign(left, _left), |
|
Condition( |
|
Property(left, "HasValue"), |
|
Condition( |
|
Call(opTrueFalse, Call(left, "GetValueOrDefault", null)), |
|
left, |
|
Block( |
|
new[] { right }, |
|
Assign(right, _right), |
|
Condition( |
|
Property(right, "HasValue"), |
|
Convert( |
|
Call( |
|
Method, |
|
Call(left, "GetValueOrDefault", null), |
|
Call(right, "GetValueOrDefault", null) |
|
), |
|
Type |
|
), |
|
Constant(null, Type) |
|
) |
|
) |
|
), |
|
Constant(null, Type) |
|
) |
|
); |
|
} |
|
} |
|
|
|
// Optimized representation of simple logical expressions: |
|
// && || == != > < >= <= |
|
internal sealed class LogicalBinaryExpression : BinaryExpression |
|
{ |
|
private readonly ExpressionType _nodeType; |
|
|
|
internal LogicalBinaryExpression(ExpressionType nodeType, Expression left, Expression right) |
|
: base(left, right) |
|
{ |
|
_nodeType = nodeType; |
|
} |
|
|
|
public override Type Type |
|
{ |
|
get { return typeof(bool); } |
|
} |
|
|
|
public override ExpressionType NodeType |
|
{ |
|
get { return _nodeType; } |
|
} |
|
} |
|
|
|
// Optimized assignment node, only holds onto children |
|
internal sealed class AssignBinaryExpression : BinaryExpression |
|
{ |
|
internal AssignBinaryExpression(Expression left, Expression right) |
|
: base(left, right) |
|
{ |
|
} |
|
|
|
public override Type Type |
|
{ |
|
get { return Left.Type; } |
|
} |
|
|
|
public override ExpressionType NodeType |
|
{ |
|
get { return ExpressionType.Assign; } |
|
} |
|
} |
|
|
|
// Coalesce with conversion |
|
// This is not a frequently used node, but rather we want to save every |
|
// other BinaryExpression from holding onto the null conversion lambda |
|
internal sealed class CoalesceConversionBinaryExpression : BinaryExpression |
|
{ |
|
private readonly LambdaExpression _conversion; |
|
|
|
internal CoalesceConversionBinaryExpression(Expression left, Expression right, LambdaExpression conversion) |
|
: base(left, right) |
|
{ |
|
_conversion = conversion; |
|
} |
|
|
|
internal override LambdaExpression GetConversion() |
|
{ |
|
return _conversion; |
|
} |
|
|
|
public override ExpressionType NodeType |
|
{ |
|
get { return ExpressionType.Coalesce; } |
|
} |
|
|
|
public override Type Type |
|
{ |
|
get { return Right.Type; } |
|
} |
|
} |
|
|
|
// OpAssign with conversion |
|
// This is not a frequently used node, but rather we want to save every |
|
// other BinaryExpression from holding onto the null conversion lambda |
|
internal sealed class OpAssignMethodConversionBinaryExpression : MethodBinaryExpression |
|
{ |
|
private readonly LambdaExpression _conversion; |
|
|
|
internal OpAssignMethodConversionBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion) |
|
: base(nodeType, left, right, type, method) |
|
{ |
|
_conversion = conversion; |
|
} |
|
|
|
internal override LambdaExpression GetConversion() |
|
{ |
|
return _conversion; |
|
} |
|
} |
|
|
|
// Class that handles most binary expressions |
|
// If needed, it can be optimized even more (often Type == left.Type) |
|
internal class SimpleBinaryExpression : BinaryExpression |
|
{ |
|
private readonly ExpressionType _nodeType; |
|
private readonly Type _type; |
|
|
|
internal SimpleBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type) |
|
: base(left, right) |
|
{ |
|
_nodeType = nodeType; |
|
_type = type; |
|
} |
|
|
|
public sealed override ExpressionType NodeType |
|
{ |
|
get { return _nodeType; } |
|
} |
|
|
|
public sealed override Type Type |
|
{ |
|
get { return _type; } |
|
} |
|
} |
|
|
|
// Class that handles binary expressions with a method |
|
// If needed, it can be optimized even more (often Type == method.ReturnType) |
|
internal class MethodBinaryExpression : SimpleBinaryExpression |
|
{ |
|
private readonly MethodInfo _method; |
|
|
|
internal MethodBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method) |
|
: base(nodeType, left, right, type) |
|
{ |
|
_method = method; |
|
} |
|
|
|
internal override MethodInfo GetMethod() |
|
{ |
|
return _method; |
|
} |
|
} |
|
|
|
public partial class Expression |
|
{ |
|
#region Assign |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see ref="F:ExpressionType.Assign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Assign(Expression left, Expression right) |
|
{ |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
TypeHelper.ValidateType(left.Type); |
|
TypeHelper.ValidateType(right.Type); |
|
if (!TypeHelper.AreReferenceAssignable(left.Type, right.Type)) |
|
{ |
|
throw Error.ExpressionTypeDoesNotMatchAssignment(right.Type, left.Type); |
|
} |
|
return new AssignBinaryExpression(left, right); |
|
} |
|
|
|
#endregion Assign |
|
|
|
private static BinaryExpression GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) |
|
{ |
|
// try exact match first |
|
var method = GetUserDefinedBinaryOperator(binaryType, left.Type, right.Type, name); |
|
if (method != null) |
|
{ |
|
return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method); |
|
} |
|
// try lifted call |
|
if (left.Type.IsNullableType() && right.Type.IsNullableType()) |
|
{ |
|
var nnLeftType = left.Type.GetNonNullableType(); |
|
var nnRightType = right.Type.GetNonNullableType(); |
|
method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name); |
|
if (method != null && method.ReturnType.IsValueType && !method.ReturnType.IsNullableType()) |
|
{ |
|
if (method.ReturnType != typeof(bool) || liftToNull) |
|
{ |
|
return new MethodBinaryExpression(binaryType, left, right, method.ReturnType.GetNullableType(), method); |
|
} |
|
else |
|
{ |
|
return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method); |
|
} |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
private static BinaryExpression GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull) |
|
{ |
|
Debug.Assert(method != null); |
|
ValidateOperator(method); |
|
var pms = method.GetParameters(); |
|
if (pms.Length != 2) |
|
{ |
|
throw Error.IncorrectNumberOfMethodCallArguments(method); |
|
} |
|
|
|
if (ParameterIsAssignable(pms[0], left.Type) && ParameterIsAssignable(pms[1], right.Type)) |
|
{ |
|
ValidateParamswithOperandsOrThrow(pms[0].ParameterType, left.Type, binaryType, method.Name); |
|
ValidateParamswithOperandsOrThrow(pms[1].ParameterType, right.Type, binaryType, method.Name); |
|
return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method); |
|
} |
|
// check for lifted call |
|
if (left.Type.IsNullableType() && right.Type.IsNullableType() && |
|
ParameterIsAssignable(pms[0], left.Type.GetNonNullableType()) && |
|
ParameterIsAssignable(pms[1], right.Type.GetNonNullableType()) && |
|
method.ReturnType.IsValueType && !method.ReturnType.IsNullableType()) |
|
{ |
|
if (method.ReturnType != typeof(bool) || liftToNull) |
|
{ |
|
return new MethodBinaryExpression(binaryType, left, right, method.ReturnType.GetNullableType(), method); |
|
} |
|
else |
|
{ |
|
return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method); |
|
} |
|
} |
|
throw Error.OperandTypesDoNotMatchParameters(binaryType, method.Name); |
|
} |
|
|
|
private static BinaryExpression GetMethodBasedAssignOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression conversion, bool liftToNull) |
|
{ |
|
var b = GetMethodBasedBinaryOperator(binaryType, left, right, method, liftToNull); |
|
if (conversion == null) |
|
{ |
|
// return type must be assignable back to the left type |
|
if (!TypeHelper.AreReferenceAssignable(left.Type, b.Type)) |
|
{ |
|
throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name); |
|
} |
|
} |
|
else |
|
{ |
|
// add the conversion to the result |
|
ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType); |
|
b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion); |
|
} |
|
return b; |
|
} |
|
|
|
private static BinaryExpression GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) |
|
{ |
|
var b = GetUserDefinedBinaryOperator(binaryType, name, left, right, liftToNull); |
|
if (b != null) |
|
{ |
|
var pis = b.Method.GetParameters(); |
|
ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, binaryType, name); |
|
ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, binaryType, name); |
|
return b; |
|
} |
|
throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type); |
|
} |
|
|
|
private static BinaryExpression GetUserDefinedAssignOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, LambdaExpression conversion, bool liftToNull) |
|
{ |
|
var b = GetUserDefinedBinaryOperatorOrThrow(binaryType, name, left, right, liftToNull); |
|
if (conversion == null) |
|
{ |
|
// return type must be assignable back to the left type |
|
if (!TypeHelper.AreReferenceAssignable(left.Type, b.Type)) |
|
{ |
|
throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name); |
|
} |
|
} |
|
else |
|
{ |
|
// add the conversion to the result |
|
ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType); |
|
b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion); |
|
} |
|
return b; |
|
} |
|
|
|
private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) |
|
{ |
|
// This algorithm is wrong, we should be checking for uniqueness and erroring if |
|
// it is defined on both types. |
|
var types = new[] { leftType, rightType }; |
|
var nnLeftType = leftType.GetNonNullableType(); |
|
var nnRightType = rightType.GetNonNullableType(); |
|
var method = nnLeftType.GetStaticMethod(name, types); |
|
if (method == null && leftType != rightType) |
|
{ |
|
method = nnRightType.GetStaticMethod(name, types); |
|
} |
|
|
|
if (IsLiftingConditionalLogicalOperator(leftType, rightType, method, binaryType)) |
|
{ |
|
method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name); |
|
} |
|
return method; |
|
} |
|
|
|
private static bool IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType) |
|
{ |
|
return right.IsNullableType() && |
|
left.IsNullableType() && |
|
method == null && |
|
(binaryType == ExpressionType.AndAlso || binaryType == ExpressionType.OrElse); |
|
} |
|
|
|
internal static bool ParameterIsAssignable(ParameterInfo pi, Type argType) |
|
{ |
|
var pType = pi.ParameterType; |
|
if (pType.IsByRef) |
|
{ |
|
pType = pType.GetElementType(); |
|
} |
|
|
|
return TypeHelper.AreReferenceAssignable(pType, argType); |
|
} |
|
|
|
private static void ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name) |
|
{ |
|
if (paramType.IsNullableType() && !operandType.IsNullableType()) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(exprType, name); |
|
} |
|
} |
|
|
|
private static void ValidateOperator(MethodInfo method) |
|
{ |
|
Debug.Assert(method != null); |
|
ValidateMethodInfo(method); |
|
if (!method.IsStatic) |
|
{ |
|
throw Error.UserDefinedOperatorMustBeStatic(method); |
|
} |
|
|
|
if (method.ReturnType == typeof(void)) |
|
{ |
|
throw Error.UserDefinedOperatorMustNotBeVoid(method); |
|
} |
|
} |
|
|
|
private static void ValidateMethodInfo(MethodInfo method) |
|
{ |
|
if (method.IsGenericMethodDefinition) |
|
{ |
|
throw Error.MethodIsGeneric(method); |
|
} |
|
|
|
if (method.ContainsGenericParameters) |
|
{ |
|
throw Error.MethodContainsGenericParameters(method); |
|
} |
|
} |
|
|
|
private static bool IsNullComparison(Expression left, Expression right) |
|
{ |
|
// If we have x==null, x!=null, null==x or null!=x where x is |
|
// nullable but not null, then this is treated as a call to x.HasValue |
|
// and is legal even if there is no equality operator defined on the |
|
// type of x. |
|
if (IsNullConstant(left) && !IsNullConstant(right) && right.Type.IsNullableType()) |
|
{ |
|
return true; |
|
} |
|
if (IsNullConstant(right) && !IsNullConstant(left) && left.Type.IsNullableType()) |
|
{ |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
// Note: this has different meaning than ConstantCheck.IsNull |
|
// That function attempts to determine if the result of a tree will be |
|
// null at runtime. This function is used at tree construction time and |
|
// only looks for a ConstantExpression with a null Value. It can't |
|
// become "smarter" or that would break tree construction. |
|
private static bool IsNullConstant(Expression e) |
|
{ |
|
var c = e as ConstantExpression; |
|
return c != null && c.Value == null; |
|
} |
|
|
|
private static void ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method) |
|
{ |
|
ValidateOperator(method); |
|
var pms = method.GetParameters(); |
|
if (pms.Length != 2) |
|
{ |
|
throw Error.IncorrectNumberOfMethodCallArguments(method); |
|
} |
|
|
|
if (!ParameterIsAssignable(pms[0], left)) |
|
{ |
|
if (!(left.IsNullableType() && ParameterIsAssignable(pms[0], left.GetNonNullableType()))) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name); |
|
} |
|
} |
|
if (!ParameterIsAssignable(pms[1], right)) |
|
{ |
|
if (!(right.IsNullableType() && ParameterIsAssignable(pms[1], right.GetNonNullableType()))) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name); |
|
} |
|
} |
|
if (pms[0].ParameterType != pms[1].ParameterType) |
|
{ |
|
throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name); |
|
} |
|
if (method.ReturnType != pms[0].ParameterType) |
|
{ |
|
throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name); |
|
} |
|
if (IsValidLiftedConditionalLogicalOperator(left, right, pms)) |
|
{ |
|
left = left.GetNonNullableType(); |
|
} |
|
var opTrue = TypeHelper.GetBooleanOperator(method.DeclaringType, "op_True"); |
|
var opFalse = TypeHelper.GetBooleanOperator(method.DeclaringType, "op_False"); |
|
if (opTrue == null || opTrue.ReturnType != typeof(bool) || |
|
opFalse == null || opFalse.ReturnType != typeof(bool)) |
|
{ |
|
throw Error.LogicalOperatorMustHaveBooleanOperators(nodeType, method.Name); |
|
} |
|
VerifyOpTrueFalse(nodeType, left, opFalse); |
|
VerifyOpTrueFalse(nodeType, left, opTrue); |
|
} |
|
|
|
private static void VerifyOpTrueFalse(ExpressionType nodeType, Type left, MethodInfo opTrue) |
|
{ |
|
var pmsOpTrue = opTrue.GetParameters(); |
|
if (pmsOpTrue.Length != 1) |
|
{ |
|
throw Error.IncorrectNumberOfMethodCallArguments(opTrue); |
|
} |
|
|
|
if (!ParameterIsAssignable(pmsOpTrue[0], left)) |
|
{ |
|
if (!(left.IsNullableType() && ParameterIsAssignable(pmsOpTrue[0], left.GetNonNullableType()))) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(nodeType, opTrue.Name); |
|
} |
|
} |
|
} |
|
|
|
private static bool IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms) |
|
{ |
|
return left == right && |
|
right.IsNullableType() && |
|
pms[1].ParameterType == right.GetNonNullableType(); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. |
|
/// </summary> |
|
/// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> |
|
/// <param name="left">An Expression that represents the left operand.</param> |
|
/// <param name="right">An Expression that represents the right operand.</param> |
|
/// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> |
|
public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right) |
|
{ |
|
return MakeBinary(binaryType, left, right, false, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. |
|
/// </summary> |
|
/// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> |
|
/// <param name="left">An Expression that represents the left operand.</param> |
|
/// <param name="right">An Expression that represents the right operand.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <param name="method">A MethodInfo that specifies the implementing method.</param> |
|
/// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> |
|
public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
return MakeBinary(binaryType, left, right, liftToNull, method, null); |
|
} |
|
|
|
/// |
|
/// <summary> |
|
/// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method. |
|
/// </summary> |
|
/// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param> |
|
/// <param name="left">An Expression that represents the left operand.</param> |
|
/// <param name="right">An Expression that represents the right operand.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <param name="method">A MethodInfo that specifies the implementing method.</param> |
|
/// <param name="conversion">A LambdaExpression that represents a type conversion function. This parameter is used if binaryType is Coalesce or compound assignment.</param> |
|
/// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns> |
|
public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
switch (binaryType) |
|
{ |
|
case ExpressionType.Add: |
|
return Add(left, right, method); |
|
|
|
case ExpressionType.AddChecked: |
|
return AddChecked(left, right, method); |
|
|
|
case ExpressionType.Subtract: |
|
return Subtract(left, right, method); |
|
|
|
case ExpressionType.SubtractChecked: |
|
return SubtractChecked(left, right, method); |
|
|
|
case ExpressionType.Multiply: |
|
return Multiply(left, right, method); |
|
|
|
case ExpressionType.MultiplyChecked: |
|
return MultiplyChecked(left, right, method); |
|
|
|
case ExpressionType.Divide: |
|
return Divide(left, right, method); |
|
|
|
case ExpressionType.Modulo: |
|
return Modulo(left, right, method); |
|
|
|
case ExpressionType.Power: |
|
return Power(left, right, method); |
|
|
|
case ExpressionType.And: |
|
return And(left, right, method); |
|
|
|
case ExpressionType.AndAlso: |
|
return AndAlso(left, right, method); |
|
|
|
case ExpressionType.Or: |
|
return Or(left, right, method); |
|
|
|
case ExpressionType.OrElse: |
|
return OrElse(left, right, method); |
|
|
|
case ExpressionType.LessThan: |
|
return LessThan(left, right, liftToNull, method); |
|
|
|
case ExpressionType.LessThanOrEqual: |
|
return LessThanOrEqual(left, right, liftToNull, method); |
|
|
|
case ExpressionType.GreaterThan: |
|
return GreaterThan(left, right, liftToNull, method); |
|
|
|
case ExpressionType.GreaterThanOrEqual: |
|
return GreaterThanOrEqual(left, right, liftToNull, method); |
|
|
|
case ExpressionType.Equal: |
|
return Equal(left, right, liftToNull, method); |
|
|
|
case ExpressionType.NotEqual: |
|
return NotEqual(left, right, liftToNull, method); |
|
|
|
case ExpressionType.ExclusiveOr: |
|
return ExclusiveOr(left, right, method); |
|
|
|
case ExpressionType.Coalesce: |
|
return Coalesce(left, right, conversion); |
|
|
|
case ExpressionType.ArrayIndex: |
|
return ArrayIndex(left, right); |
|
|
|
case ExpressionType.RightShift: |
|
return RightShift(left, right, method); |
|
|
|
case ExpressionType.LeftShift: |
|
return LeftShift(left, right, method); |
|
|
|
case ExpressionType.Assign: |
|
return Assign(left, right); |
|
|
|
case ExpressionType.AddAssign: |
|
return AddAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.AndAssign: |
|
return AndAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.DivideAssign: |
|
return DivideAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.ExclusiveOrAssign: |
|
return ExclusiveOrAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.LeftShiftAssign: |
|
return LeftShiftAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.ModuloAssign: |
|
return ModuloAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.MultiplyAssign: |
|
return MultiplyAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.OrAssign: |
|
return OrAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.PowerAssign: |
|
return PowerAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.RightShiftAssign: |
|
return RightShiftAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.SubtractAssign: |
|
return SubtractAssign(left, right, method, conversion); |
|
|
|
case ExpressionType.AddAssignChecked: |
|
return AddAssignChecked(left, right, method, conversion); |
|
|
|
case ExpressionType.SubtractAssignChecked: |
|
return SubtractAssignChecked(left, right, method, conversion); |
|
|
|
case ExpressionType.MultiplyAssignChecked: |
|
return MultiplyAssignChecked(left, right, method, conversion); |
|
|
|
default: |
|
throw Error.UnhandledBinary(binaryType); |
|
} |
|
} |
|
|
|
#region Equality Operators |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an equality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Equal(Expression left, Expression right) |
|
{ |
|
return Equal(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an equality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetEqualityComparisonOperator(ExpressionType.Equal, "op_Equality", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Equal, left, right, method, liftToNull); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a reference equality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ReferenceEqual(Expression left, Expression right) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (TypeHelper.HasReferenceEquality(left.Type, right.Type)) |
|
{ |
|
return new LogicalBinaryExpression(ExpressionType.Equal, left, right); |
|
} |
|
throw Error.ReferenceEqualityNotDefined(left.Type, right.Type); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression NotEqual(Expression left, Expression right) |
|
{ |
|
return NotEqual(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetEqualityComparisonOperator(ExpressionType.NotEqual, "op_Inequality", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.NotEqual, left, right, method, liftToNull); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a reference inequality comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ReferenceNotEqual(Expression left, Expression right) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (TypeHelper.HasReferenceEquality(left.Type, right.Type)) |
|
{ |
|
return new LogicalBinaryExpression(ExpressionType.NotEqual, left, right); |
|
} |
|
throw Error.ReferenceEqualityNotDefined(left.Type, right.Type); |
|
} |
|
|
|
private static BinaryExpression GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) |
|
{ |
|
// known comparison - numeric types, bools, object, enums |
|
if (left.Type == right.Type && (left.Type.IsNumeric() || |
|
left.Type == typeof(object) || |
|
left.Type.IsBool() || |
|
left.Type.GetNonNullableType().IsEnum)) |
|
{ |
|
if (left.Type.IsNullableType() && liftToNull) |
|
{ |
|
return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); |
|
} |
|
else |
|
{ |
|
return new LogicalBinaryExpression(binaryType, left, right); |
|
} |
|
} |
|
// look for user defined operator |
|
var b = GetUserDefinedBinaryOperator(binaryType, opName, left, right, liftToNull); |
|
if (b != null) |
|
{ |
|
return b; |
|
} |
|
if (TypeHelper.HasBuiltInEqualityOperator(left.Type, right.Type) || IsNullComparison(left, right)) |
|
{ |
|
if (left.Type.IsNullableType() && liftToNull) |
|
{ |
|
return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); |
|
} |
|
else |
|
{ |
|
return new LogicalBinaryExpression(binaryType, left, right); |
|
} |
|
} |
|
throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type); |
|
} |
|
|
|
#endregion Equality Operators |
|
|
|
#region Comparison Expressions |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression GreaterThan(Expression left, Expression right) |
|
{ |
|
return GreaterThan(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetComparisonOperator(ExpressionType.GreaterThan, "op_GreaterThan", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.GreaterThan, left, right, method, liftToNull); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
|
|
public static BinaryExpression LessThan(Expression left, Expression right) |
|
{ |
|
return LessThan(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetComparisonOperator(ExpressionType.LessThan, "op_LessThan", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.LessThan, left, right, method, liftToNull); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) |
|
{ |
|
return GreaterThanOrEqual(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetComparisonOperator(ExpressionType.GreaterThanOrEqual, "op_GreaterThanOrEqual", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.GreaterThanOrEqual, left, right, method, liftToNull); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression LessThanOrEqual(Expression left, Expression right) |
|
{ |
|
return LessThanOrEqual(left, right, false, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
return GetComparisonOperator(ExpressionType.LessThanOrEqual, "op_LessThanOrEqual", left, right, liftToNull); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.LessThanOrEqual, left, right, method, liftToNull); |
|
} |
|
|
|
private static BinaryExpression GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsNumeric()) |
|
{ |
|
if (left.Type.IsNullableType() && liftToNull) |
|
{ |
|
return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?)); |
|
} |
|
else |
|
{ |
|
return new LogicalBinaryExpression(binaryType, left, right); |
|
} |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(binaryType, opName, left, right, liftToNull); |
|
} |
|
|
|
#endregion Comparison Expressions |
|
|
|
#region Boolean Expressions |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression AndAlso(Expression left, Expression right) |
|
{ |
|
return AndAlso(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
Type returnType; |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type) |
|
{ |
|
if (left.Type == typeof(bool)) |
|
{ |
|
return new LogicalBinaryExpression(ExpressionType.AndAlso, left, right); |
|
} |
|
else if (left.Type == typeof(bool?)) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.AndAlso, left, right, left.Type); |
|
} |
|
} |
|
method = GetUserDefinedBinaryOperator(ExpressionType.AndAlso, left.Type, right.Type, "op_BitwiseAnd"); |
|
if (method != null) |
|
{ |
|
ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method); |
|
returnType = (left.Type.IsNullableType() && method.ReturnType == left.Type.GetNonNullableType()) ? left.Type : method.ReturnType; |
|
return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method); |
|
} |
|
throw Error.BinaryOperatorNotDefined(ExpressionType.AndAlso, left.Type, right.Type); |
|
} |
|
ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method); |
|
returnType = (left.Type.IsNullableType() && method.ReturnType == left.Type.GetNonNullableType()) ? left.Type : method.ReturnType; |
|
return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression OrElse(Expression left, Expression right) |
|
{ |
|
return OrElse(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
Type returnType; |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type) |
|
{ |
|
if (left.Type == typeof(bool)) |
|
{ |
|
return new LogicalBinaryExpression(ExpressionType.OrElse, left, right); |
|
} |
|
else if (left.Type == typeof(bool?)) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.OrElse, left, right, left.Type); |
|
} |
|
} |
|
method = GetUserDefinedBinaryOperator(ExpressionType.OrElse, left.Type, right.Type, "op_BitwiseOr"); |
|
if (method != null) |
|
{ |
|
ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method); |
|
returnType = (left.Type.IsNullableType() && method.ReturnType == left.Type.GetNonNullableType()) ? left.Type : method.ReturnType; |
|
return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method); |
|
} |
|
throw Error.BinaryOperatorNotDefined(ExpressionType.OrElse, left.Type, right.Type); |
|
} |
|
ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method); |
|
returnType = (left.Type.IsNullableType() && method.ReturnType == left.Type.GetNonNullableType()) ? left.Type : method.ReturnType; |
|
return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method); |
|
} |
|
|
|
#endregion Boolean Expressions |
|
|
|
#region Coalescing Expressions |
|
|
|
/// <summary> |
|
/// Creates a BinaryExpression that represents a coalescing operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left and Right properties set to the specified values.</returns> |
|
public static BinaryExpression Coalesce(Expression left, Expression right) |
|
{ |
|
return Coalesce(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a BinaryExpression that represents a coalescing operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="conversion">A LambdaExpression to set the Conversion property equal to.</param> |
|
/// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left, Right and Conversion properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
|
|
if (conversion == null) |
|
{ |
|
var resultType = ValidateCoalesceArgTypes(left.Type, right.Type); |
|
return new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, resultType); |
|
} |
|
|
|
if (left.Type.IsValueType && !left.Type.IsNullableType()) |
|
{ |
|
throw Error.CoalesceUsedOnNonNullType(); |
|
} |
|
|
|
var delegateType = conversion.Type; |
|
Debug.Assert(typeof(MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(MulticastDelegate)); |
|
var method = delegateType.GetMethod("Invoke"); |
|
if (method.ReturnType == typeof(void)) |
|
{ |
|
throw Error.UserDefinedOperatorMustNotBeVoid(conversion); |
|
} |
|
var pms = method.GetParameters(); |
|
Debug.Assert(pms.Length == conversion.Parameters.Count); |
|
if (pms.Length != 1) |
|
{ |
|
throw Error.IncorrectNumberOfMethodCallArguments(conversion); |
|
} |
|
// The return type must match exactly. |
|
// We could weaken this restriction and |
|
// say that the return type must be assignable to from |
|
// the return type of the lambda. |
|
if (method.ReturnType != right.Type) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString()); |
|
} |
|
// The parameter of the conversion lambda must either be assignable |
|
// from the erased or unerased type of the left hand side. |
|
if (!ParameterIsAssignable(pms[0], left.Type.GetNonNullableType()) && |
|
!ParameterIsAssignable(pms[0], left.Type)) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString()); |
|
} |
|
return new CoalesceConversionBinaryExpression(left, right, conversion); |
|
} |
|
|
|
private static Type ValidateCoalesceArgTypes(Type left, Type right) |
|
{ |
|
var leftStripped = left.GetNonNullableType(); |
|
if (left.IsValueType && !left.IsNullableType()) |
|
{ |
|
throw Error.CoalesceUsedOnNonNullType(); |
|
} |
|
else if (left.IsNullableType() && TypeHelper.IsImplicitlyConvertible(right, leftStripped)) |
|
{ |
|
return leftStripped; |
|
} |
|
else if (TypeHelper.IsImplicitlyConvertible(right, left)) |
|
{ |
|
return left; |
|
} |
|
else if (TypeHelper.IsImplicitlyConvertible(leftStripped, right)) |
|
{ |
|
return right; |
|
} |
|
else |
|
{ |
|
throw Error.ArgumentTypesMustMatch(); |
|
} |
|
} |
|
|
|
#endregion Coalescing Expressions |
|
|
|
#region Arithmetic Expressions |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Add(Expression left, Expression right) |
|
{ |
|
return Add(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression AddAssign(Expression left, Expression right) |
|
{ |
|
return AddAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return AddAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
|
|
public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.AddAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssign, "op_Addition", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.AddAssign, left, right, method, conversion, true); |
|
} |
|
|
|
private static void ValidateOpAssignConversionLambda(LambdaExpression conversion, Expression left, MethodInfo method, ExpressionType nodeType) |
|
{ |
|
var delegateType = conversion.Type; |
|
Debug.Assert(typeof(MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(MulticastDelegate)); |
|
var mi = delegateType.GetMethod("Invoke"); |
|
var pms = mi.GetParameters(); |
|
Debug.Assert(pms.Length == conversion.Parameters.Count); |
|
if (pms.Length != 1) |
|
{ |
|
throw Error.IncorrectNumberOfMethodCallArguments(conversion); |
|
} |
|
if (mi.ReturnType != left.Type) |
|
{ |
|
throw Error.OperandTypesDoNotMatchParameters(nodeType, conversion.ToString()); |
|
} |
|
if (method != null) |
|
{ |
|
// The parameter type of conversion lambda must be the same as the return type of the overload method |
|
if (pms[0].ParameterType != method.ReturnType) |
|
{ |
|
throw Error.OverloadOperatorTypeDoesNotMatchConversionType(nodeType, conversion.ToString()); |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to |
|
/// <see cref="F:ExpressionType.AddAssignChecked"/> and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> |
|
/// properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AddAssignChecked(Expression left, Expression right) |
|
{ |
|
return AddAssignChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return AddAssignChecked(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
|
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.AddAssignChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssignChecked, "op_Addition", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.AddAssignChecked, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression AddChecked(Expression left, Expression right) |
|
{ |
|
return AddChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.AddChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.AddChecked, "op_Addition", left, right, false); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.AddChecked, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Subtract(Expression left, Expression right) |
|
{ |
|
return Subtract(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Subtract, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Subtract, "op_Subtraction", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Subtract, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression SubtractAssign(Expression left, Expression right) |
|
{ |
|
return SubtractAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return SubtractAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.SubtractAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssign, "op_Subtraction", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.SubtractAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression SubtractAssignChecked(Expression left, Expression right) |
|
{ |
|
return SubtractAssignChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return SubtractAssignChecked(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.SubtractAssignChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssignChecked, "op_Subtraction", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.SubtractAssignChecked, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression SubtractChecked(Expression left, Expression right) |
|
{ |
|
return SubtractChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.SubtractChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.SubtractChecked, "op_Subtraction", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.SubtractChecked, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Divide(Expression left, Expression right) |
|
{ |
|
return Divide(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Divide, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Divide, "op_Division", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Divide, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression DivideAssign(Expression left, Expression right) |
|
{ |
|
return DivideAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return DivideAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.DivideAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.DivideAssign, "op_Division", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.DivideAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Modulo(Expression left, Expression right) |
|
{ |
|
return Modulo(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Modulo, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Modulo, "op_Modulus", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Modulo, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression ModuloAssign(Expression left, Expression right) |
|
{ |
|
return ModuloAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return ModuloAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.ModuloAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ModuloAssign, "op_Modulus", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.ModuloAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Multiply(Expression left, Expression right) |
|
{ |
|
return Multiply(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Multiply, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Multiply, "op_Multiply", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Multiply, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression MultiplyAssign(Expression left, Expression right) |
|
{ |
|
return MultiplyAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return MultiplyAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.MultiplyAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssign, "op_Multiply", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right) |
|
{ |
|
return MultiplyAssignChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return MultiplyAssignChecked(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.MultiplyAssignChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssignChecked, "op_Multiply", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssignChecked, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression MultiplyChecked(Expression left, Expression right) |
|
{ |
|
return MultiplyChecked(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsArithmetic()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.MultiplyChecked, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.MultiplyChecked, "op_Multiply", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.MultiplyChecked, left, right, method, true); |
|
} |
|
|
|
private static bool IsSimpleShift(Type left, Type right) |
|
{ |
|
return left.IsInteger() |
|
&& right.GetNonNullableType() == typeof(int); |
|
} |
|
|
|
private static Type GetResultTypeOfShift(Type left, Type right) |
|
{ |
|
if (!left.IsNullableType() && right.IsNullableType()) |
|
{ |
|
// lift the result type to Nullable<T> |
|
return typeof(Nullable<>).MakeGenericType(left); |
|
} |
|
return left; |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression LeftShift(Expression left, Expression right) |
|
{ |
|
return LeftShift(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (IsSimpleShift(left.Type, right.Type)) |
|
{ |
|
var resultType = GetResultTypeOfShift(left.Type, right.Type); |
|
return new SimpleBinaryExpression(ExpressionType.LeftShift, left, right, resultType); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.LeftShift, "op_LeftShift", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.LeftShift, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression LeftShiftAssign(Expression left, Expression right) |
|
{ |
|
return LeftShiftAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return LeftShiftAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (IsSimpleShift(left.Type, right.Type)) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
var resultType = GetResultTypeOfShift(left.Type, right.Type); |
|
return new SimpleBinaryExpression(ExpressionType.LeftShiftAssign, left, right, resultType); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.LeftShiftAssign, "op_LeftShift", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.LeftShiftAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression RightShift(Expression left, Expression right) |
|
{ |
|
return RightShift(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (IsSimpleShift(left.Type, right.Type)) |
|
{ |
|
var resultType = GetResultTypeOfShift(left.Type, right.Type); |
|
return new SimpleBinaryExpression(ExpressionType.RightShift, left, right, resultType); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.RightShift, "op_RightShift", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.RightShift, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression RightShiftAssign(Expression left, Expression right) |
|
{ |
|
return RightShiftAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return RightShiftAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (IsSimpleShift(left.Type, right.Type)) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
var resultType = GetResultTypeOfShift(left.Type, right.Type); |
|
return new SimpleBinaryExpression(ExpressionType.RightShiftAssign, left, right, resultType); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.RightShiftAssign, "op_RightShift", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.RightShiftAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression And(Expression left, Expression right) |
|
{ |
|
return And(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression And(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.And, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.And, "op_BitwiseAnd", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.And, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression AndAssign(Expression left, Expression right) |
|
{ |
|
return AndAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return AndAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.AndAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AndAssign, "op_BitwiseAnd", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.AndAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Or(Expression left, Expression right) |
|
{ |
|
return Or(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Or(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.Or, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Or, "op_BitwiseOr", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Or, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression OrAssign(Expression left, Expression right) |
|
{ |
|
return OrAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return OrAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.OrAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.OrAssign, "op_BitwiseOr", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.OrAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression ExclusiveOr(Expression left, Expression right) |
|
{ |
|
return ExclusiveOr(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ExclusiveOr(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
return new SimpleBinaryExpression(ExpressionType.ExclusiveOr, left, right, left.Type); |
|
} |
|
return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.ExclusiveOr, "op_ExclusiveOr", left, right, true); |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.ExclusiveOr, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right) |
|
{ |
|
return ExclusiveOrAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return ExclusiveOrAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
if (left.Type == right.Type && left.Type.IsIntegerOrBool()) |
|
{ |
|
// conversion is not supported for binary ops on arithmetic types without operator overloading |
|
if (conversion != null) |
|
{ |
|
throw Error.ConversionIsNotSupportedForArithmeticTypes(); |
|
} |
|
return new SimpleBinaryExpression(ExpressionType.ExclusiveOrAssign, left, right, left.Type); |
|
} |
|
return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ExclusiveOrAssign, "op_ExclusiveOr", left, right, conversion, true); |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.ExclusiveOrAssign, left, right, method, conversion, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression Power(Expression left, Expression right) |
|
{ |
|
return Power(left, right, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression Power(Expression left, Expression right, MethodInfo method) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
var mathType = typeof(Math); |
|
method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public); |
|
if (method == null) |
|
{ |
|
throw Error.BinaryOperatorNotDefined(ExpressionType.Power, left.Type, right.Type); |
|
} |
|
} |
|
return GetMethodBasedBinaryOperator(ExpressionType.Power, left, right, method, true); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns> |
|
public static BinaryExpression PowerAssign(Expression left, Expression right) |
|
{ |
|
return PowerAssign(left, right, null, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method) |
|
{ |
|
return PowerAssign(left, right, method, null); |
|
} |
|
|
|
/// <summary> |
|
/// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression. |
|
/// </summary> |
|
/// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param> |
|
/// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param> |
|
/// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param> |
|
/// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param> |
|
/// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> |
|
/// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>, |
|
/// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values. |
|
/// </returns> |
|
public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) |
|
{ |
|
RequiresCanRead(left, "left"); |
|
RequiresCanWrite(left, "left"); |
|
RequiresCanRead(right, "right"); |
|
if (method == null) |
|
{ |
|
var mathType = typeof(Math); |
|
method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public); |
|
if (method == null) |
|
{ |
|
throw Error.BinaryOperatorNotDefined(ExpressionType.PowerAssign, left.Type, right.Type); |
|
} |
|
} |
|
return GetMethodBasedAssignOperator(ExpressionType.PowerAssign, left, right, method, conversion, true); |
|
} |
|
|
|
#endregion Arithmetic Expressions |
|
|
|
#region ArrayIndex Expression |
|
|
|
/// <summary> |
|
/// Creates a BinaryExpression that represents applying an array index operator to an array of rank one. |
|
/// </summary> |
|
/// <param name="array">An Expression to set the Left property equal to.</param> |
|
/// <param name="index">An Expression to set the Right property equal to.</param> |
|
/// <returns>A BinaryExpression that has the NodeType property equal to ArrayIndex and the Left and Right properties set to the specified values.</returns> |
|
public static BinaryExpression ArrayIndex(Expression array, Expression index) |
|
{ |
|
RequiresCanRead(array, "array"); |
|
RequiresCanRead(index, "index"); |
|
if (index.Type != typeof(int)) |
|
{ |
|
throw Error.ArgumentMustBeArrayIndexType(); |
|
} |
|
|
|
var arrayType = array.Type; |
|
if (!arrayType.IsArray) |
|
{ |
|
throw Error.ArgumentMustBeArray(); |
|
} |
|
if (arrayType.GetArrayRank() != 1) |
|
{ |
|
throw Error.IncorrectNumberOfIndexes(); |
|
} |
|
|
|
return new SimpleBinaryExpression(ExpressionType.ArrayIndex, array, index, arrayType.GetElementType()); |
|
} |
|
|
|
#endregion ArrayIndex Expression |
|
} |
|
} |
|
|
|
#endif |