#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.Diagnostics; using System.Dynamic.Utils; using System.Reflection; using System.Runtime.CompilerServices; using LinqInternal.Core; namespace System.Linq.Expressions.Reimplement { /// /// Represents an expression that has a unary operator. /// [DebuggerTypeProxy(typeof(UnaryExpressionProxy))] public sealed class UnaryExpression : Expression { private readonly Expression _operand; private readonly MethodInfo _method; private readonly ExpressionType _nodeType; private readonly Type _type; internal UnaryExpression(ExpressionType nodeType, Expression expression, Type type, MethodInfo method) { _operand = expression; _method = method; _nodeType = nodeType; _type = type; } /// /// Gets the static type of the expression that this represents. (Inherited from .) /// /// The that represents the static type of the expression. public override Type Type { get { return _type; } } /// /// Returns the node type of this . (Inherited from .) /// /// The that represents this expression. public override ExpressionType NodeType { get { return _nodeType; } } /// /// Gets the operand of the unary operation. /// /// An that represents the operand of the unary operation. public Expression Operand { get { return _operand; } } /// /// Gets the implementing method for the unary operation. /// /// The that represents the implementing method. public MethodInfo Method { get { return _method; } } /// /// Gets a value that indicates whether the expression tree node represents a lifted call to an operator. /// /// true if the node represents a lifted call; otherwise, false. public bool IsLifted { get { if (NodeType == ExpressionType.TypeAs || NodeType == ExpressionType.Quote || NodeType == ExpressionType.Throw) { return false; } var operandIsNullable = _operand.Type.IsNullableType(); var resultIsNullable = Type.IsNullableType(); if (_method != null) { return (operandIsNullable && _method.GetParameters()[0].ParameterType != _operand.Type) || (resultIsNullable && _method.ReturnType != Type); } return operandIsNullable || resultIsNullable; } } /// /// 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. /// /// true if the operator's return type is lifted to a nullable type; otherwise, false. public bool IsLiftedToNull { get { return IsLifted && Type.IsNullableType(); } } protected internal override Expression Accept(ExpressionVisitor visitor) { return visitor.VisitUnary(this); } /// /// Gets a value that indicates whether the expression tree node can be reduced. /// public override bool CanReduce { get { switch (_nodeType) { case ExpressionType.PreIncrementAssign: case ExpressionType.PreDecrementAssign: case ExpressionType.PostIncrementAssign: case ExpressionType.PostDecrementAssign: return true; } return false; } } /// /// Reduces the 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. /// /// The reduced expression. public override Expression Reduce() { if (CanReduce) { switch (_operand.NodeType) { case ExpressionType.Index: return ReduceIndex(); case ExpressionType.MemberAccess: return ReduceMember(); default: return ReduceVariable(); } } return this; } private bool IsPrefix { get { return _nodeType == ExpressionType.PreIncrementAssign || _nodeType == ExpressionType.PreDecrementAssign; } } private UnaryExpression FunctionalOp(Expression operand) { ExpressionType functional; if (_nodeType == ExpressionType.PreIncrementAssign || _nodeType == ExpressionType.PostIncrementAssign) { functional = ExpressionType.Increment; } else { functional = ExpressionType.Decrement; } return new UnaryExpression(functional, operand, operand.Type, _method); } private Expression ReduceVariable() { if (IsPrefix) { // (op) var // ... is reduced into ... // var = op(var) return Assign(_operand, FunctionalOp(_operand)); } // var (op) // ... is reduced into ... // temp = var // var = op(var) // temp var temp = Parameter(_operand.Type, null); return Block( new[] { temp }, Assign(temp, _operand), Assign(_operand, FunctionalOp(temp)), temp ); } private Expression ReduceMember() { var member = (MemberExpression)_operand; if (member.Expression == null) { //static member, reduce the same as variable return ReduceVariable(); } else { var temp1 = Parameter(member.Expression.Type, null); var initTemp1 = Assign(temp1, member.Expression); member = MakeMemberAccess(temp1, member.Member); if (IsPrefix) { // (op) value.member // ... is reduced into ... // temp1 = value // temp1.member = op(temp1.member) return Block( new[] { temp1 }, initTemp1, Assign(member, FunctionalOp(member)) ); } // value.member (op) // ... is reduced into ... // temp1 = value // temp2 = temp1.member // temp1.member = op(temp2) // temp2 var temp2 = Parameter(member.Type, null); return Block( new[] { temp1, temp2 }, initTemp1, Assign(temp2, member), Assign(member, FunctionalOp(temp2)), temp2 ); } } private Expression ReduceIndex() { // left[a0, a1, ... aN] (op) // // ... is reduced into ... // // tempObj = left // tempArg0 = a0 // ... // tempArgN = aN // tempValue = tempObj[tempArg0, ... tempArgN] // tempObj[tempArg0, ... tempArgN] = op(tempValue) // tempValue var prefix = IsPrefix; var index = (IndexExpression)_operand; var count = index.Arguments.Count; var block = new Expression[count + (prefix ? 2 : 4)]; var temps = new ParameterExpression[count + (prefix ? 1 : 2)]; var args = new ParameterExpression[count]; var i = 0; temps[i] = Parameter(index.Object.Type, null); block[i] = Assign(temps[i], index.Object); i++; while (i <= count) { var arg = index.Arguments[i - 1]; args[i - 1] = temps[i] = Parameter(arg.Type, null); block[i] = Assign(temps[i], arg); i++; } index = MakeIndex(temps[0], index.Indexer, new TrueReadOnlyCollection(args)); if (!prefix) { var lastTemp = temps[i] = Parameter(index.Type, null); block[i] = Assign(temps[i], index); i++; Debug.Assert(i == temps.Length); block[i++] = Assign(index, FunctionalOp(lastTemp)); block[i++] = lastTemp; } else { Debug.Assert(i == temps.Length); block[i++] = Assign(index, FunctionalOp(index)); } Debug.Assert(i == block.Length); return Block(new TrueReadOnlyCollection(temps), new TrueReadOnlyCollection(block)); } /// /// 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. /// /// The property of the result. /// This expression if no children changed, or an expression with the updated children. public UnaryExpression Update(Expression operand) { if (operand == Operand) { return this; } return MakeUnary(NodeType, operand, Type, Method); } } public partial class Expression { /// /// Creates a , given an operand, by calling the appropriate factory method. /// /// The that specifies the type of unary operation. /// An that represents the operand. /// The that specifies the type to be converted to (pass null if not applicable). /// The that results from calling the appropriate factory method. /// Thrown when does not correspond to a unary expression. /// Thrown when is null. public static UnaryExpression MakeUnary(ExpressionType unaryType, Expression operand, Type type) { return MakeUnary(unaryType, operand, type, null); } /// /// Creates a , given an operand and implementing method, by calling the appropriate factory method. /// /// The that specifies the type of unary operation. /// An that represents the operand. /// The that specifies the type to be converted to (pass null if not applicable). /// The that represents the implementing method. /// The that results from calling the appropriate factory method. /// Thrown when does not correspond to a unary expression. /// Thrown when is null. public static UnaryExpression MakeUnary(ExpressionType unaryType, Expression operand, Type type, MethodInfo method) { switch (unaryType) { case ExpressionType.Negate: return Negate(operand, method); case ExpressionType.NegateChecked: return NegateChecked(operand, method); case ExpressionType.Not: return Not(operand, method); case ExpressionType.IsFalse: return IsFalse(operand, method); case ExpressionType.IsTrue: return IsTrue(operand, method); case ExpressionType.OnesComplement: return OnesComplement(operand, method); case ExpressionType.ArrayLength: return ArrayLength(operand); case ExpressionType.Convert: return Convert(operand, type, method); case ExpressionType.ConvertChecked: return ConvertChecked(operand, type, method); case ExpressionType.Throw: return Throw(operand, type); case ExpressionType.TypeAs: return TypeAs(operand, type); case ExpressionType.Quote: return Quote(operand); case ExpressionType.UnaryPlus: return UnaryPlus(operand, method); case ExpressionType.Unbox: return Unbox(operand, type); case ExpressionType.Increment: return Increment(operand, method); case ExpressionType.Decrement: return Decrement(operand, method); case ExpressionType.PreIncrementAssign: return PreIncrementAssign(operand, method); case ExpressionType.PostIncrementAssign: return PostIncrementAssign(operand, method); case ExpressionType.PreDecrementAssign: return PreDecrementAssign(operand, method); case ExpressionType.PostDecrementAssign: return PostDecrementAssign(operand, method); default: throw Error.UnhandledUnary(unaryType); } } private static UnaryExpression GetUserDefinedUnaryOperatorOrThrow(ExpressionType unaryType, string name, Expression operand) { var u = GetUserDefinedUnaryOperator(unaryType, name, operand); if (u != null) { ValidateParamswithOperandsOrThrow(u.Method.GetParameters()[0].ParameterType, operand.Type, unaryType, name); return u; } throw Error.UnaryOperatorNotDefined(unaryType, operand.Type); } private static UnaryExpression GetUserDefinedUnaryOperator(ExpressionType unaryType, string name, Expression operand) { var operandType = operand.Type; var types = new[] { operandType }; var nnOperandType = operandType.GetNonNullableType(); var method = nnOperandType.GetStaticMethod(name, types); if (method != null) { return new UnaryExpression(unaryType, operand, method.ReturnType, method); } // try lifted call if (operandType.IsNullableType()) { types[0] = nnOperandType; method = nnOperandType.GetStaticMethod(name, types); if (method != null && method.ReturnType.IsValueType && !method.ReturnType.IsNullableType()) { return new UnaryExpression(unaryType, operand, method.ReturnType.GetNullableType(), method); } } return null; } private static UnaryExpression GetMethodBasedUnaryOperator(ExpressionType unaryType, Expression operand, MethodInfo method) { Debug.Assert(method != null); ValidateOperator(method); var pms = method.GetParameters(); if (pms.Length != 1) { throw Error.IncorrectNumberOfMethodCallArguments(method); } if (ParameterIsAssignable(pms[0], operand.Type)) { ValidateParamswithOperandsOrThrow(pms[0].ParameterType, operand.Type, unaryType, method.Name); return new UnaryExpression(unaryType, operand, method.ReturnType, method); } // check for lifted call if (operand.Type.IsNullableType() && ParameterIsAssignable(pms[0], operand.Type.GetNonNullableType()) && method.ReturnType.IsValueType && !method.ReturnType.IsNullableType()) { return new UnaryExpression(unaryType, operand, method.ReturnType.GetNullableType(), method); } throw Error.OperandTypesDoNotMatchParameters(unaryType, method.Name); } private static UnaryExpression GetUserDefinedConversionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType) { var u = GetUserDefinedConversion(coercionType, expression, convertToType); if (u != null) { return u; } throw Error.CoercionOperatorNotDefined(expression.Type, convertToType); } private static UnaryExpression GetUserDefinedConversion(ExpressionType coercionType, Expression expression, Type convertToType) { var method = TypeHelper.GetUserDefinedConversionMethod(expression.Type, convertToType, false); if (method != null) { return new UnaryExpression(coercionType, expression, convertToType, method); } else { return null; } } private static UnaryExpression GetMethodBasedCoercionOperator(ExpressionType unaryType, Expression operand, Type convertToType, MethodInfo method) { Debug.Assert(method != null); ValidateOperator(method); var pms = method.GetParameters(); if (pms.Length != 1) { throw Error.IncorrectNumberOfMethodCallArguments(method); } if (ParameterIsAssignable(pms[0], operand.Type) && method.ReturnType == convertToType) { return new UnaryExpression(unaryType, operand, method.ReturnType, method); } // check for lifted call if ((operand.Type.IsNullableType() || convertToType.IsNullableType()) && ParameterIsAssignable(pms[0], operand.Type.GetNonNullableType()) && method.ReturnType == convertToType.GetNonNullableType()) { return new UnaryExpression(unaryType, operand, convertToType, method); } throw Error.OperandTypesDoNotMatchParameters(unaryType, method.Name); } /// /// Creates a that represents an arithmetic negation operation. /// /// An to set the property equal to. /// A that has the property equal to and the properties set to the specified value. /// Thrown when is null. /// Thrown when the unary minus operator is not defined for public static UnaryExpression Negate(Expression expression) { return Negate(expression, null); } /// /// Creates a that represents an arithmetic negation operation. /// /// An to set the property equal to. /// A to set the property equal to. /// A that has the property equal to and the and properties set to the specified value. /// Thrown when is null. /// Thrown when is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. /// Thown when is null and the unary minus operator is not defined for expression.Type or expression.Type (or its corresponding non-nullable type if it is a nullable value type) is not assignable to the argument type of the method represented by method. public static UnaryExpression Negate(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsArithmetic() && !expression.Type.IsUnsignedInteger()) { return new UnaryExpression(ExpressionType.Negate, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.Negate, "op_UnaryNegation", expression); } return GetMethodBasedUnaryOperator(ExpressionType.Negate, expression, method); } /// /// Creates a that represents a unary plus operation. /// /// An to set the property equal to. /// A that has the property equal to and the property set to the specified value. /// Thrown when is null. /// Thown when the unary minus operator is not defined for expression.Type. public static UnaryExpression UnaryPlus(Expression expression) { return UnaryPlus(expression, null); } /// /// Creates a that represents a unary plus operation. /// /// An to set the property equal to. /// A to set the property equal to. /// A that has the property equal to and the and property set to the specified value. /// Thrown when is null. /// Thrown when is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. /// Thown when is null and the unary minus operator is not defined for expression.Type or expression.Type (or its corresponding non-nullable type if it is a nullable value type) is not assignable to the argument type of the method represented by method. public static UnaryExpression UnaryPlus(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsArithmetic()) { return new UnaryExpression(ExpressionType.UnaryPlus, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.UnaryPlus, "op_UnaryPlus", expression); } return GetMethodBasedUnaryOperator(ExpressionType.UnaryPlus, expression, method); } /// Creates a that represents an arithmetic negation operation that has overflow checking. /// A that has the property equal to and the property set to the specified value. /// An to set the property equal to. /// /// Thrown when is null. /// Thrown when the unary minus operator is not defined for .Type. public static UnaryExpression NegateChecked(Expression expression) { return NegateChecked(expression, null); } ///Creates a that represents an arithmetic negation operation that has overflow checking. The implementing method can be specified. ///A that has the property equal to and the and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. /// /// is null. /// /// is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. /// /// is null and the unary minus operator is not defined for .Type.-or-.Type (or its corresponding non-nullable type if it is a nullable value type) is not assignable to the argument type of the method represented by . public static UnaryExpression NegateChecked(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsArithmetic() && !expression.Type.IsUnsignedInteger()) { return new UnaryExpression(ExpressionType.NegateChecked, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.NegateChecked, "op_UnaryNegation", expression); } return GetMethodBasedUnaryOperator(ExpressionType.NegateChecked, expression, method); } ///Creates a that represents a bitwise complement operation. ///A that has the property equal to and the property set to the specified value. ///An to set the property equal to. /// /// is null. ///The unary not operator is not defined for .Type. public static UnaryExpression Not(Expression expression) { return Not(expression, null); } ///Creates a that represents a bitwise complement operation. The implementing method can be specified. ///A that has the property equal to and the and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. /// /// is null. /// /// is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. /// /// is null and the unary not operator is not defined for .Type.-or-.Type (or its corresponding non-nullable type if it is a nullable value type) is not assignable to the argument type of the method represented by . public static UnaryExpression Not(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsIntegerOrBool()) { return new UnaryExpression(ExpressionType.Not, expression, expression.Type, null); } var u = GetUserDefinedUnaryOperator(ExpressionType.Not, "op_LogicalNot", expression); if (u != null) { return u; } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.Not, "op_OnesComplement", expression); } return GetMethodBasedUnaryOperator(ExpressionType.Not, expression, method); } /// /// Returns whether the expression evaluates to false. /// /// An to evaluate. /// An instance of . public static UnaryExpression IsFalse(Expression expression) { return IsFalse(expression, null); } /// /// Returns whether the expression evaluates to false. /// ///An to evaluate. ///A that represents the implementing method. /// An instance of . public static UnaryExpression IsFalse(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsBool()) { return new UnaryExpression(ExpressionType.IsFalse, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.IsFalse, "op_False", expression); } return GetMethodBasedUnaryOperator(ExpressionType.IsFalse, expression, method); } /// /// Returns whether the expression evaluates to true. /// /// An to evaluate. /// An instance of . public static UnaryExpression IsTrue(Expression expression) { return IsTrue(expression, null); } /// /// Returns whether the expression evaluates to true. /// ///An to evaluate. ///A that represents the implementing method. /// An instance of . public static UnaryExpression IsTrue(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsBool()) { return new UnaryExpression(ExpressionType.IsTrue, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.IsTrue, "op_True", expression); } return GetMethodBasedUnaryOperator(ExpressionType.IsTrue, expression, method); } /// /// Returns the expression representing the ones complement. /// ///An . /// An instance of . public static UnaryExpression OnesComplement(Expression expression) { return OnesComplement(expression, null); } /// /// Returns the expression representing the ones complement. /// /// An . /// A that represents the implementing method. /// An instance of . public static UnaryExpression OnesComplement(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsInteger()) { return new UnaryExpression(ExpressionType.OnesComplement, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.OnesComplement, "op_OnesComplement", expression); } return GetMethodBasedUnaryOperator(ExpressionType.OnesComplement, expression, method); } ///Creates a that represents an explicit reference or boxing conversion where null is supplied if the conversion fails. ///A that has the property equal to and the and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. /// /// or is null. public static UnaryExpression TypeAs(Expression expression, Type type) { RequiresCanRead(expression, "expression"); ContractUtils.RequiresNotNull(type, "type"); TypeHelper.ValidateType(type); if (type.IsValueType && !type.IsNullableType()) { throw Error.IncorrectTypeForTypeAs(type); } return new UnaryExpression(ExpressionType.TypeAs, expression, type, null); } /// /// Creates a that represents an explicit unboxing. /// /// An to unbox. /// The new of the expression. /// An instance of . public static UnaryExpression Unbox(Expression expression, Type type) { RequiresCanRead(expression, "expression"); ContractUtils.RequiresNotNull(type, "type"); if (!expression.Type.IsInterface && expression.Type != typeof(object)) { throw Error.InvalidUnboxType(); } if (!type.IsValueType) { throw Error.InvalidUnboxType(); } TypeHelper.ValidateType(type); return new UnaryExpression(ExpressionType.Unbox, expression, type, null); } ///Creates a that represents a conversion operation. ///A that has the property equal to and the and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. /// /// or is null. ///No conversion operator is defined between .Type and . public static UnaryExpression Convert(Expression expression, Type type) { return Convert(expression, type, null); } ///Creates a that represents a conversion operation for which the implementing method is specified. ///A that has the property equal to and the , , and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. ///A to set the property equal to. /// /// or is null. /// /// is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. ///More than one method that matches the description was found. ///No conversion operator is defined between .Type and .-or-.Type is not assignable to the argument type of the method represented by .-or-The return type of the method represented by is not assignable to .-or-.Type or is a nullable value type and the corresponding non-nullable value type does not equal the argument type or the return type, respectively, of the method represented by . public static UnaryExpression Convert(Expression expression, Type type, MethodInfo method) { RequiresCanRead(expression, "expression"); ContractUtils.RequiresNotNull(type, "type"); TypeHelper.ValidateType(type); if (method == null) { if (TypeHelper.HasIdentityPrimitiveOrNullableConversion(expression.Type, type) || TypeHelper.HasReferenceConversion(expression.Type, type)) { return new UnaryExpression(ExpressionType.Convert, expression, type, null); } return GetUserDefinedConversionOrThrow(ExpressionType.Convert, expression, type); } return GetMethodBasedCoercionOperator(ExpressionType.Convert, expression, type, method); } ///Creates a that represents a conversion operation that throws an exception if the target type is overflowed. ///A that has the property equal to and the and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. /// /// or is null. ///No conversion operator is defined between .Type and . public static UnaryExpression ConvertChecked(Expression expression, Type type) { return ConvertChecked(expression, type, null); } ///Creates a that represents a conversion operation that throws an exception if the target type is overflowed and for which the implementing method is specified. ///A that has the property equal to and the , , and properties set to the specified values. ///An to set the property equal to. ///A to set the property equal to. ///A to set the property equal to. /// /// or is null. /// /// is not null and the method it represents returns void, is not static (Shared in Visual Basic), or does not take exactly one argument. ///More than one method that matches the description was found. ///No conversion operator is defined between .Type and .-or-.Type is not assignable to the argument type of the method represented by .-or-The return type of the method represented by is not assignable to .-or-.Type or is a nullable value type and the corresponding non-nullable value type does not equal the argument type or the return type, respectively, of the method represented by . public static UnaryExpression ConvertChecked(Expression expression, Type type, MethodInfo method) { RequiresCanRead(expression, "expression"); ContractUtils.RequiresNotNull(type, "type"); TypeHelper.ValidateType(type); if (method == null) { if (TypeHelper.HasIdentityPrimitiveOrNullableConversion(expression.Type, type)) { return new UnaryExpression(ExpressionType.ConvertChecked, expression, type, null); } if (TypeHelper.HasReferenceConversion(expression.Type, type)) { return new UnaryExpression(ExpressionType.Convert, expression, type, null); } return GetUserDefinedConversionOrThrow(ExpressionType.ConvertChecked, expression, type); } return GetMethodBasedCoercionOperator(ExpressionType.ConvertChecked, expression, type, method); } ///Creates a that represents getting the length of a one-dimensional array. ///A that has the property equal to and the property equal to . ///An to set the property equal to. /// /// is null. /// ///.Type does not represent an array type. public static UnaryExpression ArrayLength(Expression array) { ContractUtils.RequiresNotNull(array, "array"); if (!array.Type.IsArray || !typeof(Array).IsAssignableFrom(array.Type)) { throw Error.ArgumentMustBeArray(); } if (array.Type.GetArrayRank() != 1) { throw Error.ArgumentMustBeSingleDimensionalArrayType(); } return new UnaryExpression(ExpressionType.ArrayLength, array, typeof(int), null); } ///Creates a that represents an expression that has a constant value of type . ///A that has the property equal to and the property set to the specified value. ///An to set the property equal to. /// /// is null. public static UnaryExpression Quote(Expression expression) { RequiresCanRead(expression, "expression"); var validQuote = expression is LambdaExpression; if (!validQuote) { throw Error.QuotedExpressionMustBeLambda(); } return new UnaryExpression(ExpressionType.Quote, expression, expression.GetType(), null); } /// /// Creates a that represents a rethrowing of an exception. /// /// A that represents a rethrowing of an exception. public static UnaryExpression Rethrow() { return Throw(null); } /// /// Creates a that represents a rethrowing of an exception with a given type. /// ///The new of the expression. /// A that represents a rethrowing of an exception. public static UnaryExpression Rethrow(Type type) { return Throw(null, type); } /// /// Creates a that represents a throwing of an exception. /// /// An . /// A that represents the exception. public static UnaryExpression Throw(Expression value) { return Throw(value, typeof(void)); } /// /// Creates a that represents a throwing of a value with a given type. /// /// An . /// The new of the expression. /// A that represents the exception. public static UnaryExpression Throw(Expression value, Type type) { ContractUtils.RequiresNotNull(type, "type"); TypeHelper.ValidateType(type); if (value != null) { RequiresCanRead(value, "value"); if (value.Type.IsValueType) { throw Error.ArgumentMustNotHaveValueType(); } } return new UnaryExpression(ExpressionType.Throw, value, type, null); } /// /// Creates a that represents the incrementing of the expression by 1. /// /// An to increment. /// A that represents the incremented expression. public static UnaryExpression Increment(Expression expression) { return Increment(expression, null); } /// /// Creates a that represents the incrementing of the expression by 1. /// /// An to increment. ///A that represents the implementing method. /// A that represents the incremented expression. public static UnaryExpression Increment(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsArithmetic()) { return new UnaryExpression(ExpressionType.Increment, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.Increment, "op_Increment", expression); } return GetMethodBasedUnaryOperator(ExpressionType.Increment, expression, method); } /// /// Creates a that represents the decrementing of the expression by 1. /// /// An to decrement. /// A that represents the decremented expression. public static UnaryExpression Decrement(Expression expression) { return Decrement(expression, null); } /// /// Creates a that represents the decrementing of the expression by 1. /// /// An to decrement. ///A that represents the implementing method. /// A that represents the decremented expression. public static UnaryExpression Decrement(Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); if (method == null) { if (expression.Type.IsArithmetic()) { return new UnaryExpression(ExpressionType.Decrement, expression, expression.Type, null); } return GetUserDefinedUnaryOperatorOrThrow(ExpressionType.Decrement, "op_Decrement", expression); } return GetMethodBasedUnaryOperator(ExpressionType.Decrement, expression, method); } /// /// Creates a that increments the expression by 1 /// and assigns the result back to the expression. /// /// An to apply the operations on. /// A that represents the resultant expression. public static UnaryExpression PreIncrementAssign(Expression expression) { return MakeOpAssignUnary(ExpressionType.PreIncrementAssign, expression, null); } /// /// Creates a that increments the expression by 1 /// and assigns the result back to the expression. /// /// An to apply the operations on. /// A that represents the implementing method. /// A that represents the resultant expression. public static UnaryExpression PreIncrementAssign(Expression expression, MethodInfo method) { return MakeOpAssignUnary(ExpressionType.PreIncrementAssign, expression, method); } /// /// Creates a that decrements the expression by 1 /// and assigns the result back to the expression. /// /// An to apply the operations on. /// A that represents the resultant expression. public static UnaryExpression PreDecrementAssign(Expression expression) { return MakeOpAssignUnary(ExpressionType.PreDecrementAssign, expression, null); } /// /// Creates a that decrements the expression by 1 /// and assigns the result back to the expression. /// /// An to apply the operations on. /// A that represents the implementing method. /// A that represents the resultant expression. public static UnaryExpression PreDecrementAssign(Expression expression, MethodInfo method) { return MakeOpAssignUnary(ExpressionType.PreDecrementAssign, expression, method); } /// /// Creates a that represents the assignment of the expression /// followed by a subsequent increment by 1 of the original expression. /// /// An to apply the operations on. /// A that represents the resultant expression. public static UnaryExpression PostIncrementAssign(Expression expression) { return MakeOpAssignUnary(ExpressionType.PostIncrementAssign, expression, null); } /// /// Creates a that represents the assignment of the expression /// followed by a subsequent increment by 1 of the original expression. /// /// An to apply the operations on. /// A that represents the implementing method. /// A that represents the resultant expression. public static UnaryExpression PostIncrementAssign(Expression expression, MethodInfo method) { return MakeOpAssignUnary(ExpressionType.PostIncrementAssign, expression, method); } /// /// Creates a that represents the assignment of the expression /// followed by a subsequent decrement by 1 of the original expression. /// /// An to apply the operations on. /// A that represents the resultant expression. public static UnaryExpression PostDecrementAssign(Expression expression) { return MakeOpAssignUnary(ExpressionType.PostDecrementAssign, expression, null); } /// /// Creates a that represents the assignment of the expression /// followed by a subsequent decrement by 1 of the original expression. /// /// An to apply the operations on. /// A that represents the implementing method. /// A that represents the resultant expression. public static UnaryExpression PostDecrementAssign(Expression expression, MethodInfo method) { return MakeOpAssignUnary(ExpressionType.PostDecrementAssign, expression, method); } private static UnaryExpression MakeOpAssignUnary(ExpressionType kind, Expression expression, MethodInfo method) { RequiresCanRead(expression, "expression"); RequiresCanWrite(expression, "expression"); UnaryExpression result; if (method == null) { if (expression.Type.IsArithmetic()) { return new UnaryExpression(kind, expression, expression.Type, null); } string name; if (kind == ExpressionType.PreIncrementAssign || kind == ExpressionType.PostIncrementAssign) { name = "op_Increment"; } else { name = "op_Decrement"; } result = GetUserDefinedUnaryOperatorOrThrow(kind, name, expression); } else { result = GetMethodBasedUnaryOperator(kind, expression, method); } // return type must be assignable back to the operand type if (!TypeHelper.AreReferenceAssignable(expression.Type, result.Type)) { throw Error.UserDefinedOpMustHaveValidReturnType(kind, method.Name); } return result; } } } #endif