private static Func <Closure, object> Binary(BinaryExpression binaryExpression, ConstantExpression[] constantsExprs, ParameterExpression[] localsExprs) { var leftFn = Expression(binaryExpression.Left, constantsExprs, localsExprs); var rightFn = Expression(binaryExpression.Right, constantsExprs, localsExprs); var opAddition = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Addition"); var opBitwiseAnd = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_BitwiseAnd"); var opDivision = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Division"); var opEquality = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Equality"); var opExclusiveOr = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_ExclusiveOr"); var opGreaterThan = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_GreaterThan"); var opGreaterThanOrEqual = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_GreaterThanOrEqual"); var opLessThan = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_LessThan"); var opLessThanOrEqual = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_LessThanOrEqual"); var opModulus = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Modulus"); var opMultiply = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Multiply"); var opBitwiseOr = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_BitwiseOr"); var opSubtraction = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Subtraction"); var isNullable = IsNullable(binaryExpression.Left) || IsNullable(binaryExpression.Right); return(closure => { switch (binaryExpression.NodeType) { case ExpressionType.AndAlso: return closure.Unbox <bool>(leftFn(closure)) && closure.Unbox <bool>(rightFn(closure)); case ExpressionType.OrElse: return closure.Unbox <bool>(leftFn(closure)) || closure.Unbox <bool>(rightFn(closure)); } var left = leftFn(closure); var right = rightFn(closure); if ( isNullable && (left == null || right == null) && binaryExpression.NodeType != ExpressionType.Coalesce && binaryExpression.NodeType != ExpressionType.ArrayIndex ) { // ReSharper disable once SwitchStatementMissingSomeCases switch (binaryExpression.NodeType) { case ExpressionType.Equal: return closure.Box(left == right); case ExpressionType.NotEqual: return closure.Box(left != right); case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: return closure.Box(false); default: return null; } } switch (binaryExpression.NodeType) { case ExpressionType.Add: case ExpressionType.AddChecked: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opAddition); case ExpressionType.And: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opBitwiseAnd); case ExpressionType.ArrayIndex: return closure.Is <int[]>(right) ? closure.Unbox <Array>(left).GetValue(closure.Unbox <int[]>(right)) : closure.Unbox <Array>(left).GetValue(closure.Unbox <int>(right)); case ExpressionType.Coalesce: return left ?? right; case ExpressionType.Divide: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opDivision); case ExpressionType.Equal: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opEquality); case ExpressionType.NotEqual: return closure.Box(closure.Unbox <bool>(Intrinsics.BinaryOperation(closure, left, right, ExpressionType.Equal, opEquality)) == false); case ExpressionType.ExclusiveOr: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opExclusiveOr); case ExpressionType.GreaterThan: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opGreaterThan); case ExpressionType.GreaterThanOrEqual: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opGreaterThanOrEqual); case ExpressionType.LeftShift: case ExpressionType.Power: case ExpressionType.RightShift: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, null); case ExpressionType.LessThan: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opLessThan); case ExpressionType.LessThanOrEqual: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opLessThanOrEqual); case ExpressionType.Modulo: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opModulus); case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opMultiply); case ExpressionType.Or: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opBitwiseOr); case ExpressionType.Subtract: case ExpressionType.SubtractChecked: return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opSubtraction); } throw new InvalidOperationException(string.Format(Properties.Resources.EXCEPTION_COMPIL_UNKNOWNBINARYEXPRTYPE, binaryExpression.Type)); }); }