#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