//
/*
The MIT License (MIT)
Copyright (c) 2016-2020 Maksim Volkau
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// ReSharper disable CoVariantArrayConversion
/*
// Lists the target platforms that are Not supported by FEC - simplifies the direct referencing of Expression.cs file
// Don't forget to uncomment #endif at the end of file
*/
#if !PCL && !NET35 && !NET40 && !NET403 && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETCOREAPP1_0 && !NETCOREAPP1_1
#define SUPPORTS_FAST_EXPRESSION_COMPILER
#endif
#if SUPPORTS_FAST_EXPRESSION_COMPILER
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using static System.Environment;
using SysExpr = System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.LightExpression
{
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
/// Facade for constructing Expression.
public abstract class Expression
{
/// Expression node type.
public abstract ExpressionType NodeType { get; }
/// All expressions should have a Type.
public abstract Type Type { get; }
internal struct LightAndSysExpr
{
public Expression LightExpr;
public SysExpr SysExpr;
}
public SysExpr ToExpression()
{
var exprsConverted = new LiveCountArray(Tools.Empty());
return ToExpression(ref exprsConverted);
}
/// Converts back to respective System Expression, so you may Compile it by usual means.
internal SysExpr ToExpression(ref LiveCountArray exprsConverted)
{
var i = exprsConverted.Count - 1;
while (i != -1 && !ReferenceEquals(exprsConverted.Items[i].LightExpr, this)) --i;
if (i != -1)
return exprsConverted.Items[i].SysExpr;
var sysExpr = CreateSysExpression(ref exprsConverted);
ref var item = ref exprsConverted.PushSlot();
item.LightExpr = this;
item.SysExpr = sysExpr;
return sysExpr;
}
internal abstract SysExpr CreateSysExpression(ref LiveCountArray exprsConverted);
/// Tries to print the expression in its constructing syntax - helpful to get it from debug and put into code to test,
/// e.g. .
///
/// NOTE: It is trying hard but the Parameter expression are not consolidated into one. Hopefully R# will help you to re-factor them into a single variable.
public abstract string CodeString { get; }
/// Converts to Expression and outputs its as string
public override string ToString() => ToExpression().ToString();
/// Reduces the Expression to simple ones
public virtual Expression Reduce() => this;
internal static SysExpr[] ToExpressions(IReadOnlyList exprs, ref LiveCountArray exprsConverted)
{
if (exprs.Count == 0)
return Tools.Empty();
if (exprs.Count == 1)
return new[] { exprs[0].ToExpression(ref exprsConverted) };
var result = new SysExpr[exprs.Count];
for (var i = 0; i < result.Length; ++i)
result[i] = exprs[i].ToExpression(ref exprsConverted);
return result;
}
internal static string ToParamsCode(IReadOnlyList arguments) where T : Expression
{
if (arguments.Count == 0)
return $"new {typeof(T).Name}[0]";
var s = new StringBuilder();
for (var i = 0; i < arguments.Count; i++)
{
if (i > 0)
s.Append(",");
s.Append(arguments[i].CodeString);
}
return s.ToString();
}
public static ParameterExpression Parameter(Type type, string name = null) =>
new ParameterExpression(type.IsByRef ? type.GetElementType() : type, name, type.IsByRef);
public static ParameterExpression Variable(Type type, string name = null) => Parameter(type, name);
public static readonly ConstantExpression NullConstant = new TypedConstantExpression(null, typeof(object));
public static readonly ConstantExpression FalseConstant = new ConstantExpression(false);
public static readonly ConstantExpression TrueConstant = new ConstantExpression(true);
public static readonly ConstantExpression ZeroConstant = new ConstantExpression(0);
public static ConstantExpression Constant(bool value) =>
value ? TrueConstant : FalseConstant;
public static ConstantExpression Constant(int value) =>
value == 0 ? ZeroConstant : new TypedConstantExpression(value);
public static ConstantExpression Constant(T value) =>
new TypedConstantExpression(value);
public static ConstantExpression Constant(object value)
{
if (value == null)
return NullConstant;
if (value is bool b)
return b ? TrueConstant : FalseConstant;
if (value is int n)
return n == 0 ? ZeroConstant : new TypedConstantExpression(n);
return new ConstantExpression(value);
}
public static ConstantExpression Constant(object value, Type type) =>
new TypedConstantExpression(value, type);
public static NewExpression New(Type type)
{
if (type.IsValueType())
return new NewValueTypeExpression(type);
foreach (var x in type.GetTypeInfo().DeclaredConstructors)
if (x.GetParameters().Length == 0)
return new NewExpression(x);
throw new ArgumentException($"The type {type} is missing the default constructor");
}
public static NewExpression New(ConstructorInfo ctor, params Expression[] arguments) =>
arguments == null || arguments.Length == 0 ? new NewExpression(ctor): new ManyArgumentsNewExpression(ctor, arguments);
public static NewExpression New(ConstructorInfo ctor, IEnumerable arguments)
{
var args = arguments.AsReadOnlyList();
return args == null || args.Count == 0 ? new NewExpression(ctor) : new ManyArgumentsNewExpression(ctor, args);
}
public static NewExpression New(ConstructorInfo ctor) => new NewExpression(ctor);
public static NewExpression New(ConstructorInfo ctor, Expression arg) =>
new OneArgumentNewExpression(ctor, arg);
public static NewExpression New(ConstructorInfo ctor, Expression arg0, Expression arg1) =>
new TwoArgumentsNewExpression(ctor, arg0, arg1);
public static NewExpression New(ConstructorInfo ctor, Expression arg0, Expression arg1, Expression arg2) =>
new ThreeArgumentsNewExpression(ctor, arg0, arg1, arg2);
public static NewExpression New(ConstructorInfo ctor,
Expression arg0, Expression arg1, Expression arg2, Expression arg3) =>
new FourArgumentsNewExpression(ctor, arg0, arg1, arg2, arg3);
public static NewExpression New(ConstructorInfo ctor,
Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) =>
new FiveArgumentsNewExpression(ctor, arg0, arg1, arg2, arg3, arg4);
public static MethodCallExpression Call(MethodInfo method, params Expression[] arguments)
{
if (arguments == null || arguments.Length == 0)
return new MethodCallExpression(method);
return new ManyArgumentsMethodCallExpression(method, arguments);
}
public static MethodCallExpression Call(MethodInfo method, IEnumerable arguments)
{
var args = arguments.AsReadOnlyList();
if (args == null || args.Count == 0)
return new MethodCallExpression(method);
return new ManyArgumentsMethodCallExpression(method, args);
}
public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments)
{
if (arguments == null || arguments.Length == 0)
return new InstanceMethodCallExpression(instance, method);
return new InstanceManyArgumentsMethodCallExpression(instance, method, arguments);
}
public static MethodCallExpression Call(Expression instance, MethodInfo method, IEnumerable arguments)
{
var args = arguments.AsReadOnlyList();
if (args == null || args.Count == 0)
return new InstanceMethodCallExpression(instance, method);
return new InstanceManyArgumentsMethodCallExpression(instance, method, args);
}
public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, params Expression[] arguments)
{
if (arguments == null || arguments.Length == 0)
return new MethodCallExpression(type.FindMethod(methodName, typeArguments, arguments, isStatic: true));
return new ManyArgumentsMethodCallExpression(type.FindMethod(methodName, typeArguments, arguments, isStatic: true), arguments);
}
public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, IEnumerable arguments)
{
var args = arguments.AsReadOnlyList();
if (args == null || args.Count == 0)
return new MethodCallExpression(type.FindMethod(methodName, typeArguments, args, isStatic: true));
return new ManyArgumentsMethodCallExpression(type.FindMethod(methodName, typeArguments, args, isStatic: true), args);
}
public static MethodCallExpression Call(Expression instance, string methodName, Type[] typeArguments, params Expression[] arguments)
{
if (arguments == null || arguments.Length == 0)
return new InstanceMethodCallExpression(instance, instance.Type.FindMethod(methodName, typeArguments, arguments));
return new InstanceManyArgumentsMethodCallExpression(instance, instance.Type.FindMethod(methodName, typeArguments, arguments), arguments);
}
public static MethodCallExpression Call(Expression instance, string methodName, Type[] typeArguments, IEnumerable arguments)
{
var args = arguments.AsReadOnlyList();
if (args == null || args.Count == 0)
return new InstanceMethodCallExpression(instance, instance.Type.FindMethod(methodName, typeArguments, args));
return new InstanceManyArgumentsMethodCallExpression(instance, instance.Type.FindMethod(methodName, typeArguments, args), args);
}
public static MethodCallExpression Call(MethodInfo method) =>
new MethodCallExpression(method);
public static MethodCallExpression Call(Expression instance, MethodInfo method) =>
instance == null
? new MethodCallExpression(method)
: new InstanceMethodCallExpression(instance, method);
public static MethodCallExpression Call(MethodInfo method, Expression argument) =>
new OneArgumentMethodCallExpression(method, argument);
public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression argument) =>
instance == null
? new OneArgumentMethodCallExpression(method, argument)
: new InstanceOneArgumentMethodCallExpression(instance, method, argument);
public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1) =>
new TwoArgumentsMethodCallExpression(method, arg0, arg1);
public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1) =>
instance == null
? new TwoArgumentsMethodCallExpression(method, arg0, arg1)
: new InstanceTwoArgumentsMethodCallExpression(instance, method, arg0, arg1);
public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2) =>
new ThreeArgumentsMethodCallExpression(method, arg0, arg1, arg2);
public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1, Expression arg2) =>
instance == null
? new ThreeArgumentsMethodCallExpression(method, arg0, arg1, arg2)
: new InstanceThreeArgumentsMethodCallExpression(instance, method, arg0, arg1, arg2);
public static MethodCallExpression Call(MethodInfo method,
Expression arg0, Expression arg1, Expression arg2, Expression arg3) =>
new FourArgumentsMethodCallExpression(method, arg0, arg1, arg2, arg3);
public static MethodCallExpression Call(Expression instance, MethodInfo method,
Expression arg0, Expression arg1, Expression arg2, Expression arg3) =>
instance == null
? new FourArgumentsMethodCallExpression(method, arg0, arg1, arg2, arg3)
: new InstanceFourArgumentsMethodCallExpression(instance, method, arg0, arg1, arg2, arg3);
public static MethodCallExpression Call(MethodInfo method,
Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) =>
new FiveArgumentsMethodCallExpression(method, arg0, arg1, arg2, arg3, arg4);
public static MethodCallExpression Call(Expression instance, MethodInfo method,
Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) =>
instance == null
? new FiveArgumentsMethodCallExpression(method, arg0, arg1, arg2, arg3, arg4)
: new InstanceFiveArgumentsMethodCallExpression(instance, method, arg0, arg1, arg2, arg3, arg4);
public static Expression CallIfNotNull(Expression instance, MethodInfo method) =>
CallIfNotNull(instance, method, Tools.Empty());
public static Expression CallIfNotNull(Expression instance, MethodInfo method, IEnumerable arguments)
{
var instanceVar = Parameter(instance.Type, "f");
return Block(instanceVar,
Assign(instanceVar, instance),
Condition(Equal(instanceVar, Constant(null)),
Constant(null), Call(instanceVar, method, arguments)));
}
public static MemberExpression Property(PropertyInfo property) =>
new PropertyExpression(null, property);
public static MemberExpression Property(Expression instance, PropertyInfo property) =>
new PropertyExpression(instance, property);
public static MemberExpression Property(Expression expression, string propertyName) =>
Property(expression, expression.Type.FindProperty(propertyName)
?? throw new ArgumentException($"Declared property with the name '{propertyName}' is not found in '{expression.Type}'", nameof(propertyName)));
public static IndexExpression Property(Expression instance, PropertyInfo indexer, params Expression[] arguments) =>
new IndexExpression(instance, indexer, arguments);
public static IndexExpression Property(Expression instance, PropertyInfo indexer, IEnumerable arguments) =>
new IndexExpression(instance, indexer, arguments.AsReadOnlyList());
public static MemberExpression PropertyOrField(Expression expression, string propertyName) =>
expression.Type.FindProperty(propertyName) != null ?
(MemberExpression)new PropertyExpression(expression, expression.Type.FindProperty(propertyName)
?? throw new ArgumentException($"Declared property with the name '{propertyName}' is not found in '{expression.Type}'", nameof(propertyName))) :
new FieldExpression(expression, expression.Type.FindField(propertyName)
?? throw new ArgumentException($"Declared field with the name '{propertyName}' is not found '{expression.Type}'", nameof(propertyName)));
public static MemberExpression MakeMemberAccess(Expression expression, MemberInfo member)
{
if (member is FieldInfo field)
return Field(expression, field);
if (member is PropertyInfo property)
return Property(expression, property);
throw new ArgumentException($"Member is not field or property: {member}", nameof(member));
}
public static IndexExpression MakeIndex(Expression instance, PropertyInfo indexer, IEnumerable arguments) =>
indexer != null ? Property(instance, indexer, arguments) : ArrayAccess(instance, arguments);
public static IndexExpression ArrayAccess(Expression array, params Expression[] indexes) =>
new IndexExpression(array, null, indexes);
public static IndexExpression ArrayAccess(Expression array, IEnumerable indexes) =>
new IndexExpression(array, null, indexes.AsReadOnlyList());
public static MemberExpression Field(FieldInfo field) =>
new FieldExpression(null, field);
public static MemberExpression Field(Expression instance, FieldInfo field) =>
new FieldExpression(instance, field);
public static MemberExpression Field(Expression instance, string fieldName) =>
new FieldExpression(instance, instance.Type.FindField(fieldName));
/// Creates a UnaryExpression that represents a bitwise complement operation.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to Not and the Operand property set to the specified value.
public static UnaryExpression Not(Expression expression) =>
new UnaryExpression(ExpressionType.Not, expression);
/// Creates a UnaryExpression that represents an explicit reference or boxing conversion where null is supplied if the conversion fails.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A UnaryExpression that has the NodeType property equal to TypeAs and the Operand and Type properties set to the specified values.
public static UnaryExpression TypeAs(Expression expression, Type type) =>
new TypedUnaryExpression(ExpressionType.TypeAs, expression, type);
public static TypeBinaryExpression TypeEqual(Expression operand, Type type) =>
new TypeBinaryExpression(ExpressionType.TypeEqual, operand, type);
public static TypeBinaryExpression TypeIs(Expression operand, Type type) =>
new TypeBinaryExpression(ExpressionType.TypeIs, operand, type);
/// Creates a UnaryExpression that represents an expression for obtaining the length of a one-dimensional array.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to ArrayLength and the Operand property equal to array.
public static UnaryExpression ArrayLength(Expression array) =>
new TypedUnaryExpression(ExpressionType.ArrayLength, array);
/// Creates a UnaryExpression that represents a type conversion operation.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A UnaryExpression that has the NodeType property equal to Convert and the Operand and Type properties set to the specified values.
public static UnaryExpression Convert(Expression expression, Type type) =>
new TypedUnaryExpression(ExpressionType.Convert, expression, type);
/// Creates a UnaryExpression that represents a type conversion operation.
/// A Type to set the Type property equal to.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to Convert and the Operand and Type properties set to the specified values.
public static UnaryExpression Convert(Expression expression) =>
new TypedUnaryExpression(ExpressionType.Convert, expression);
/// Creates a UnaryExpression that represents a conversion operation for which the implementing method is specified.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A MethodInfo to set the Method property equal to.
/// A UnaryExpression that has the NodeType property equal to Convert and the Operand, Type, and Method properties set to the specified values.
public static UnaryExpression Convert(Expression expression, Type type, MethodInfo method) =>
new ConvertWithMethodUnaryExpression(ExpressionType.Convert, expression, type, method);
/// Creates a UnaryExpression that represents a conversion operation that throws an exception if the target type is overflowed.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A UnaryExpression that has the NodeType property equal to ConvertChecked and the Operand and Type properties set to the specified values.
public static UnaryExpression ConvertChecked(Expression expression, Type type) =>
new TypedUnaryExpression(ExpressionType.ConvertChecked, expression, type);
/// Creates a UnaryExpression that represents a conversion operation that throws an exception if the target type is overflowed and for which the implementing method is specified.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A MethodInfo to set the Method property equal to.
/// A UnaryExpression that has the NodeType property equal to ConvertChecked and the Operand, Type, and Method properties set to the specified values.
public static UnaryExpression ConvertChecked(Expression expression, Type type, MethodInfo method) =>
new ConvertWithMethodUnaryExpression(ExpressionType.ConvertChecked, expression, type, method);
/// Creates a UnaryExpression that represents the decrementing of the expression by 1.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the decremented expression.
public static UnaryExpression Decrement(Expression expression) =>
new UnaryExpression(ExpressionType.Decrement, expression);
/// Creates a UnaryExpression that represents the incrementing of the expression value by 1.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the incremented expression.
public static UnaryExpression Increment(Expression expression) =>
new UnaryExpression(ExpressionType.Increment, expression);
/// Returns whether the expression evaluates to false.
/// An Expression to set the Operand property equal to.
/// An instance of UnaryExpression.
public static UnaryExpression IsFalse(Expression expression) =>
new TypedUnaryExpression(ExpressionType.IsFalse, expression);
/// Returns whether the expression evaluates to true.
/// An Expression to set the Operand property equal to.
/// An instance of UnaryExpression.
public static UnaryExpression IsTrue(Expression expression) =>
new TypedUnaryExpression(ExpressionType.IsTrue, expression);
/// Creates a UnaryExpression, given an operand, by calling the appropriate factory method.
/// The ExpressionType that specifies the type of unary operation.
/// An Expression that represents the operand.
/// The Type that specifies the type to be converted to (pass null if not applicable).
/// The UnaryExpression that results from calling the appropriate factory method.
public static UnaryExpression MakeUnary(ExpressionType unaryType, Expression operand, Type type) =>
type == null
? new UnaryExpression(unaryType, operand)
: new TypedUnaryExpression(unaryType, operand, type);
/// Creates a UnaryExpression that represents an arithmetic negation operation.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to Negate and the Operand property set to the specified value.
public static UnaryExpression Negate(Expression expression) =>
new UnaryExpression(ExpressionType.Negate, expression);
/// Creates a UnaryExpression that represents an arithmetic negation operation that has overflow checking.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to NegateChecked and the Operand property set to the specified value.
public static UnaryExpression NegateChecked(Expression expression) =>
new UnaryExpression(ExpressionType.NegateChecked, expression);
/// Returns the expression representing the ones complement.
/// An Expression to set the Operand property equal to.
/// An instance of UnaryExpression.
public static UnaryExpression OnesComplement(Expression expression) =>
new UnaryExpression(ExpressionType.OnesComplement, expression);
/// Creates a UnaryExpression that increments the expression by 1 and assigns the result back to the expression.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the resultant expression.
public static UnaryExpression PreIncrementAssign(Expression expression) =>
new UnaryExpression(ExpressionType.PreIncrementAssign, expression);
/// Creates a UnaryExpression that represents the assignment of the expression followed by a subsequent increment by 1 of the original expression.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the resultant expression.
public static UnaryExpression PostIncrementAssign(Expression expression) =>
new UnaryExpression(ExpressionType.PostIncrementAssign, expression);
/// Creates a UnaryExpression that decrements the expression by 1 and assigns the result back to the expression.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the resultant expression.
public static UnaryExpression PreDecrementAssign(Expression expression) =>
new UnaryExpression(ExpressionType.PreDecrementAssign, expression);
/// Creates a UnaryExpression that represents the assignment of the expression followed by a subsequent decrement by 1 of the original expression.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the resultant expression.
public static UnaryExpression PostDecrementAssign(Expression expression) =>
new UnaryExpression(ExpressionType.PostDecrementAssign, expression);
/// Creates a UnaryExpression that represents an expression that has a constant value of type Expression.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to Quote and the Operand property set to the specified value.
public static UnaryExpression Quote(Expression expression) =>
new UnaryExpression(ExpressionType.Quote, expression);
/// Creates a UnaryExpression that represents a unary plus operation.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that has the NodeType property equal to UnaryPlus and the Operand property set to the specified value.
public static UnaryExpression UnaryPlus(Expression expression) =>
new UnaryExpression(ExpressionType.UnaryPlus, expression);
/// Creates a UnaryExpression that represents an explicit unboxing.
/// An Expression to set the Operand property equal to.
/// A Type to set the Type property equal to.
/// A UnaryExpression that has the NodeType property equal to unbox and the Operand and Type properties set to the specified values.
public static UnaryExpression Unbox(Expression expression, Type type) =>
new TypedUnaryExpression(ExpressionType.Unbox, expression, type);
public static LambdaExpression Lambda(Expression body) =>
new LambdaExpression(Tools.GetFuncOrActionType(Tools.Empty(), body.Type),
body, body.Type);
public static LambdaExpression Lambda(Type delegateType, Expression body) =>
new LambdaExpression(delegateType, body, body.Type);
public static LambdaExpression Lambda(Type delegateType, Expression body, Type returnType) =>
new LambdaExpression(delegateType, body, returnType);
public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters) =>
Lambda(Tools.GetFuncOrActionType(Tools.GetParamTypes(parameters), body.Type), body, parameters, body.Type);
public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) =>
Lambda(delegateType, body, parameters, GetDelegateReturnType(delegateType));
public static LambdaExpression Lambda(Type delegateType, Expression body, ParameterExpression[] parameters, Type returnType) =>
parameters == null || parameters.Length == 0
? new LambdaExpression(delegateType, body, returnType)
: new ManyParametersLambdaExpression(delegateType, body, parameters, returnType);
public static Expression Lambda(Expression body) =>
new Expression(body, typeof(TDelegate).FindDelegateInvokeMethod().ReturnType);
public static Expression Lambda(Expression body, Type returnType) =>
new Expression(body, returnType);
public static Expression Lambda(Expression body, params ParameterExpression[] parameters) =>
Lambda(body, parameters, GetDelegateReturnType(typeof(TDelegate)));
public static Expression Lambda(Expression body, ParameterExpression[] parameters, Type returnType) =>
parameters == null || parameters.Length == 0
? new Expression(body, returnType)
: new ManyParametersExpression(body, parameters, returnType);
///
/// is ignored for now, the method is just for compatibility with SysExpression
///
public static Expression Lambda(Expression body, string name, params ParameterExpression[] parameters) where TDelegate : class =>
new ManyParametersExpression(body, parameters, GetDelegateReturnType(typeof(TDelegate)));
private static Type GetDelegateReturnType(Type delType)
{
var typeInfo = delType.GetTypeInfo();
if (typeInfo.IsGenericType)
{
var typeArguments = typeInfo.GenericTypeArguments;
var index = typeArguments.Length - 1;
var typeDef = typeInfo.GetGenericTypeDefinition();
if (typeDef == FuncTypes[index])
return typeArguments[index];
if (typeDef == ActionTypes[index])
return typeof(void);
}
else if (delType == typeof(Action))
return typeof(void);
return delType.FindDelegateInvokeMethod().ReturnType;
}
internal static readonly Type[] FuncTypes =
{
typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>), typeof(Func<,,,,>),
typeof(Func<,,,,,>), typeof(Func<,,,,,,>), typeof(Func<,,,,,,,>)
};
internal static readonly Type[] ActionTypes =
{
typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), typeof(Action<,,,>),
typeof(Action<,,,,>), typeof(Action<,,,,,>), typeof(Action<,,,,,,>)
};
/// Creates a BinaryExpression that represents applying an array index operator to an array of rank one.
/// A Expression to set the Left property equal to.
/// A Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to ArrayIndex and the Left and Right properties set to the specified values.
public static BinaryExpression ArrayIndex(Expression array, Expression index) =>
new ArrayIndexExpression(array, index, array.Type.GetElementType());
public static MemberAssignment Bind(MemberInfo member, Expression expression) =>
new MemberAssignment(member, expression);
public static MemberInitExpression MemberInit(NewExpression newExpr, params MemberBinding[] bindings) =>
new MemberInitExpression(newExpr, bindings);
/// Does not present in System Expression. Enables member assignment on existing instance expression.
public static MemberInitExpression MemberInit(Expression instanceExpr, params MemberBinding[] assignments) =>
new MemberInitExpression(instanceExpr, assignments);
public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers) =>
new NewArrayExpression(ExpressionType.NewArrayInit, type.MakeArrayType(), initializers);
public static NewArrayExpression NewArrayBounds(Type type, params Expression[] bounds) =>
new NewArrayExpression(ExpressionType.NewArrayBounds,
bounds.Length == 1 ? type.MakeArrayType() : type.MakeArrayType(bounds.Length),
bounds);
/// Creates a BinaryExpression that represents an assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Assign and the Left and Right properties set to the specified values.
public static BinaryExpression Assign(Expression left, Expression right) =>
new AssignBinaryExpression(left, right, left.Type);
/// Creates a BinaryExpression that represents raising an expression to a power and assigning the result back to the expression.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to PowerAssign and the Left and Right properties set to the specified values.
public static BinaryExpression PowerAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.PowerAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents an addition assignment operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to AddAssign and the Left and Right properties set to the specified values.
public static BinaryExpression AddAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.AddAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents an addition assignment operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to AddAssignChecked and the Left and Right properties set to the specified values.
public static BinaryExpression AddAssignChecked(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.AddAssignChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise AND assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to AndAssign and the Left and Right properties set to the specified values.
public static BinaryExpression AndAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.AndAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise XOR assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to ExclusiveOrAssign and the Left and Right properties set to the specified values.
public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.ExclusiveOrAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise left-shift assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to LeftShiftAssign and the Left and Right properties set to the specified values.
public static BinaryExpression LeftShiftAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.LeftShiftAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a remainder assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to ModuloAssign and the Left and Right properties set to the specified values.
public static BinaryExpression ModuloAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.ModuloAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise OR assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to OrAssign and the Left and Right properties set to the specified values.
public static BinaryExpression OrAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.OrAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise right-shift assignment operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to RightShiftAssign and the Left and Right properties set to the specified values.
public static BinaryExpression RightShiftAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.RightShiftAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a subtraction assignment operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to SubtractAssign and the Left and Right properties set to the specified values.
public static BinaryExpression SubtractAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.SubtractAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a subtraction assignment operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to SubtractAssignChecked and the Left and Right properties set to the specified values.
public static BinaryExpression SubtractAssignChecked(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.SubtractAssignChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents a multiplication assignment operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to MultiplyAssign and the Left and Right properties set to the specified values.
public static BinaryExpression MultiplyAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.MultiplyAssign, left, right, left.Type);
/// Creates a BinaryExpression that represents a multiplication assignment operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to MultiplyAssignChecked and the Left and Right properties set to the specified values.
public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.MultiplyAssignChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents a division assignment operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to DivideAssign and the Left and Right properties set to the specified values.
public static BinaryExpression DivideAssign(Expression left, Expression right) =>
new AssignBinaryExpression(ExpressionType.DivideAssign, left, right, left.Type);
public static InvocationExpression Invoke(Expression lambda, IEnumerable args) =>
new InvocationExpression(lambda, args.AsReadOnlyList(),
(lambda as LambdaExpression)?.ReturnType ?? lambda.Type.FindDelegateInvokeMethod().ReturnType);
public static InvocationExpression Invoke(Expression lambda, params Expression[] args) =>
Invoke(lambda, (IEnumerable)args);
public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse) =>
new ConditionalExpression(test, ifTrue, ifFalse);
public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse, Type type) =>
new ConditionalExpression(test, ifTrue, ifFalse, type);
public static ConditionalExpression IfThen(Expression test, Expression ifTrue) =>
Condition(test, ifTrue, Empty(), typeof(void));
public static DefaultExpression Empty() => new DefaultExpression(typeof(void));
public static DefaultExpression Default(Type type) =>
type == typeof(void) ? Empty() : new DefaultExpression(type);
public static ConditionalExpression IfThenElse(Expression test, Expression ifTrue, Expression ifFalse) =>
Condition(test, ifTrue, ifFalse, typeof(void));
/// Creates a BinaryExpression that represents an arithmetic addition operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Add and the Left and Right properties set to the specified values.
public static BinaryExpression Add(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic addition operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to AddChecked and the Left and Right properties set to the specified values.
public static BinaryExpression AddChecked(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.AddChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise XOR operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to ExclusiveOr and the Left and Right properties set to the specified values.
public static BinaryExpression ExclusiveOr(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.ExclusiveOr, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise left-shift operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to LeftShift and the Left and Right properties set to the specified values.
public static BinaryExpression LeftShift(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.LeftShift, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic remainder operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Modulo and the Left and Right properties set to the specified values.
public static BinaryExpression Modulo(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Modulo, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise OR operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Or and the Left and Right properties set to the specified values.
public static BinaryExpression Or(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Or, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise right-shift operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to RightShift and the Left and Right properties set to the specified values.
public static BinaryExpression RightShift(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.RightShift, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic subtraction operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Subtract and the Left and Right properties set to the specified values.
public static BinaryExpression Subtract(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Subtract, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic subtraction operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to SubtractChecked and the Left, Right, and Method properties set to the specified values.
public static BinaryExpression SubtractChecked(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.SubtractChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic multiplication operation that does not have overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Multiply and the Left and Right properties set to the specified values.
public static BinaryExpression Multiply(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Multiply, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic multiplication operation that has overflow checking.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to MultiplyChecked and the Left and Right properties set to the specified values.
public static BinaryExpression MultiplyChecked(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.MultiplyChecked, left, right, left.Type);
/// Creates a BinaryExpression that represents an arithmetic division operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Divide and the Left and Right properties set to the specified values.
public static BinaryExpression Divide(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Divide, left, right, left.Type);
/// Creates a BinaryExpression that represents raising a number to a power.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Power and the Left and Right properties set to the specified values.
public static BinaryExpression Power(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Power, left, right, left.Type);
/// Creates a BinaryExpression that represents a bitwise AND operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to And, and the Left and Right properties are set to the specified values.
public static BinaryExpression And(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.And, left, right, left.Type);
/// Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to AndAlso and the Left and Right properties set to the specified values.
public static BinaryExpression AndAlso(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.AndAlso, left, right, left.Type);
/// Creates a BinaryExpression that represents a conditional OR operation that evaluates the second operand only if the first operand evaluates to false.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to OrElse and the Left and Right properties set to the specified values.
public static BinaryExpression OrElse(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.OrElse, left, right, left.Type);
/// Creates a BinaryExpression that represents an equality comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Equal and the Left and Right properties set to the specified values.
public static BinaryExpression Equal(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Equal, left, right, typeof(bool));
/// Creates a BinaryExpression that represents a "greater than" numeric comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to GreaterThan and the Left and Right properties set to the specified values.
public static BinaryExpression GreaterThan(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.GreaterThan, left, right, left.Type);
/// Creates a BinaryExpression that represents a "greater than or equal" numeric comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to GreaterThanOrEqual and the Left and Right properties set to the specified values.
public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.GreaterThanOrEqual, left, right, left.Type);
/// Creates a BinaryExpression that represents a "less than" numeric comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to LessThan and the Left and Right properties set to the specified values.
public static BinaryExpression LessThan(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.LessThan, left, right, left.Type);
/// Creates a BinaryExpression that represents a " less than or equal" numeric comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to LessThanOrEqual and the Left and Right properties set to the specified values.
public static BinaryExpression LessThanOrEqual(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.LessThanOrEqual, left, right, left.Type);
/// Creates a BinaryExpression that represents an inequality comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to NotEqual and the Left and Right properties set to the specified values.
public static BinaryExpression NotEqual(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.NotEqual, left, right, typeof(bool));
public static BlockExpression Block(params Expression[] expressions) =>
Block(expressions[expressions.Length - 1].Type, Tools.Empty(), expressions);
public static BlockExpression Block(IReadOnlyList expressions) =>
Block(Tools.Empty(), expressions);
public static BlockExpression Block(IEnumerable variables, params Expression[] expressions) =>
Block(variables.AsReadOnlyList(), new List(expressions));
public static BlockExpression Block(IReadOnlyList variables, IReadOnlyList expressions) =>
Block(expressions[expressions.Count - 1].Type, variables, expressions);
public static BlockExpression Block(Type type, IEnumerable variables, params Expression[] expressions) =>
new BlockExpression(type, variables.AsReadOnlyList(), expressions.AsReadOnlyList());
public static BlockExpression Block(Type type, IEnumerable variables, IEnumerable expressions) =>
new BlockExpression(type, variables.AsReadOnlyList(), expressions.AsReadOnlyList());
public static Expression Block(ParameterExpression variable, Expression expression1, Expression expression2) =>
expression2.NodeType == ExpressionType.Throw || expression1.NodeType == ExpressionType.Throw
? (Expression)Block(new[] {variable}, expression1, expression2)
: new OneVariableTwoExpressionBlockExpression(variable, expression1, expression2);
///
/// Creates a LoopExpression with the given body and (optional) break target.
///
/// The body of the loop.
/// The break target used by the loop body, if required.
/// The created LoopExpression.
public static LoopExpression Loop(Expression body, LabelTarget @break = null) =>
@break == null ? new LoopExpression(body, null, null) : new LoopExpression(body, @break, null);
///
/// Creates a LoopExpression with the given body.
///
/// The body of the loop.
/// The break target used by the loop body.
/// The continue target used by the loop body.
/// The created LoopExpression.
public static LoopExpression Loop(Expression body, LabelTarget @break, LabelTarget @continue) =>
new LoopExpression(body, @break, @continue);
public static TryExpression TryCatch(Expression body, params CatchBlock[] handlers) =>
new TryExpression(body, null, handlers);
public static TryExpression TryCatchFinally(Expression body, Expression @finally, params CatchBlock[] handlers) =>
new TryExpression(body, @finally, handlers);
public static TryExpression TryFinally(Expression body, Expression @finally) =>
new TryExpression(body, @finally, null);
public static CatchBlock Catch(ParameterExpression variable, Expression body) =>
new CatchBlock(variable, body, null, variable.Type);
public static CatchBlock Catch(Type test, Expression body) =>
new CatchBlock(null, body, null, test);
/// Creates a UnaryExpression that represents a throwing of an exception.
/// An Expression to set the Operand property equal to.
/// A UnaryExpression that represents the exception.
public static UnaryExpression Throw(Expression value) => Throw(value, typeof(void));
/// Creates a UnaryExpression that represents a throwing of an exception with a given type.
/// An Expression to set the Operand property equal to.
/// The Type of the expression.
/// A UnaryExpression that represents the exception.
public static UnaryExpression Throw(Expression value, Type type) =>
new TypedUnaryExpression(ExpressionType.Throw, value, type);
public static LabelExpression Label(LabelTarget target, Expression defaultValue = null) =>
new LabelExpression(target, defaultValue);
public static LabelTarget Label(Type type = null, string name = null) =>
SysExpr.Label(type ?? typeof(void), name);
public static LabelTarget Label(string name) =>
SysExpr.Label(typeof(void), name);
/// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method.
/// The ExpressionType that specifies the type of binary operation.
/// An Expression that represents the left operand.
/// An Expression that represents the right operand.
/// The BinaryExpression that results from calling the appropriate factory method.
public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right)
{
switch (binaryType)
{
case ExpressionType.AddAssign:
case ExpressionType.AddAssignChecked:
case ExpressionType.AndAssign:
case ExpressionType.Assign:
case ExpressionType.DivideAssign:
case ExpressionType.ExclusiveOrAssign:
case ExpressionType.LeftShiftAssign:
case ExpressionType.ModuloAssign:
case ExpressionType.MultiplyAssign:
case ExpressionType.MultiplyAssignChecked:
case ExpressionType.OrAssign:
case ExpressionType.PowerAssign:
case ExpressionType.RightShiftAssign:
case ExpressionType.SubtractAssign:
case ExpressionType.SubtractAssignChecked:
return new AssignBinaryExpression(binaryType, left, right, left.Type);
case ExpressionType.ArrayIndex:
return ArrayIndex(left, right);
case ExpressionType.Coalesce:
return Coalesce(left, right);
default:
return new SimpleBinaryExpression(binaryType, left, right, left.Type);
}
}
public static GotoExpression MakeGoto(GotoExpressionKind kind, LabelTarget target, Expression value, Type type = null) =>
new GotoExpression(kind, target, value, type ?? typeof(void));
public static GotoExpression Break(LabelTarget target, Expression value = null, Type type = null) =>
MakeGoto(GotoExpressionKind.Break, target, value, type);
public static GotoExpression Continue(LabelTarget target, Type type = null) =>
MakeGoto(GotoExpressionKind.Continue, target, null, type);
/// Creates a BinaryExpression that represents a reference equality comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Equal and the Left and Right properties set to the specified values.
public static BinaryExpression ReferenceEqual(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Equal, left, right, typeof(bool));
/// Creates a BinaryExpression that represents a reference inequality comparison.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to NotEqual and the Left and Right properties set to the specified values.
public static BinaryExpression ReferenceNotEqual(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.NotEqual, left, right, typeof(bool));
public static GotoExpression Return(LabelTarget target, Expression value = null, Type type = null) =>
MakeGoto(GotoExpressionKind.Return, target, value, type);
public static GotoExpression Goto(LabelTarget target, Expression value = null, Type type = null) =>
MakeGoto(GotoExpressionKind.Goto, target, value, type);
public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, params SwitchCase[] cases) =>
new SwitchExpression(defaultBody.Type, switchValue, defaultBody, null, cases);
public static SwitchExpression Switch(Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) =>
new SwitchExpression(defaultBody.Type, switchValue, defaultBody, comparison, cases);
public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, params SwitchCase[] cases) =>
new SwitchExpression(type, switchValue, defaultBody, comparison, cases);
public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable cases) =>
new SwitchExpression(type, switchValue, defaultBody, comparison, cases.AsArray());
public static SwitchExpression Switch(Expression switchValue, params SwitchCase[] cases) =>
new SwitchExpression(null, switchValue, null, null, cases);
public static SwitchCase SwitchCase(Expression body, IEnumerable testValues) =>
new SwitchCase(body, testValues);
public static SwitchCase SwitchCase(Expression body, params Expression[] testValues) =>
new SwitchCase(body, testValues);
/// Creates a BinaryExpression that represents a coalescing operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A BinaryExpression that has the NodeType property equal to Coalesce and the Left and Right properties set to the specified values.
public static BinaryExpression Coalesce(Expression left, Expression right) =>
new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, GetCoalesceType(left.Type, right.Type));
/// Creates a BinaryExpression that represents a coalescing operation.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// Result type
/// A BinaryExpression that has the NodeType property equal to Coalesce and the Left and Right properties set to the specified values.
public static BinaryExpression Coalesce(Expression left, Expression right, Type type) =>
new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, type);
/// Creates a BinaryExpression that represents a coalescing operation, given a conversion function.
/// An Expression to set the Left property equal to.
/// An Expression to set the Right property equal to.
/// A LambdaExpression to set the Conversion property equal to.
/// A BinaryExpression that has the NodeType property equal to Coalesce and the Left, Right and Conversion properties set to the specified values.
public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) =>
conversion == null ?
new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, GetCoalesceType(left.Type, right.Type)) :
(BinaryExpression)new CoalesceConversionBinaryExpression(left, right, conversion);
private static Type GetCoalesceType(Type left, Type right)
{
var leftTypeInfo = left.GetTypeInfo();
if (leftTypeInfo.IsGenericType && leftTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
left = leftTypeInfo.GenericTypeArguments[0];
if (right == left)
return left;
if (leftTypeInfo.IsAssignableFrom(right.GetTypeInfo()) ||
right.IsImplicitlyBoxingConvertibleTo(left) ||
right.IsImplicitlyNumericConvertibleTo(left))
return left;
if (right.GetTypeInfo().IsAssignableFrom(leftTypeInfo) ||
left.IsImplicitlyBoxingConvertibleTo(right) ||
left.IsImplicitlyNumericConvertibleTo(right))
return right;
throw new ArgumentException($"Unable to coalesce arguments of left type of {left} and right type of {right}.");
}
}
internal static class TypeTools
{
internal static int GetFirstIndex(this IReadOnlyList source, T item)
{
if (source.Count != 0)
for (var i = 0; i < source.Count; ++i)
if (ReferenceEquals(source[i], item))
return i;
return -1;
}
internal static bool IsImplicitlyBoxingConvertibleTo(this Type source, Type target) =>
source.GetTypeInfo().IsValueType &&
(target == typeof(object) ||
target == typeof(ValueType)) ||
source.GetTypeInfo().IsEnum && target == typeof(Enum);
internal static PropertyInfo FindProperty(this Type type, string propertyName)
{
var properties = type.GetTypeInfo().DeclaredProperties.AsArray();
for (var i = 0; i < properties.Length; i++)
if (properties[i].Name == propertyName)
return properties[i];
return type.GetTypeInfo().BaseType?.FindProperty(propertyName);
}
internal static FieldInfo FindField(this Type type, string fieldName)
{
var fields = type.GetTypeInfo().DeclaredFields.AsArray();
for (var i = 0; i < fields.Length; i++)
if (fields[i].Name == fieldName)
return fields[i];
return type.GetTypeInfo().BaseType?.FindField(fieldName);
}
internal static MethodInfo FindMethod(this Type type,
string methodName, Type[] typeArgs, IReadOnlyList args, bool isStatic = false)
{
var methods = type.GetTypeInfo().DeclaredMethods.AsArray();
for (var i = 0; i < methods.Length; i++)
{
var m = methods[i];
if (isStatic == m.IsStatic && methodName == m.Name)
{
typeArgs = typeArgs ?? Type.EmptyTypes;
var mTypeArgs = m.GetGenericArguments();
if (typeArgs.Length == mTypeArgs.Length &&
(typeArgs.Length == 0 || AreTypesTheSame(typeArgs, mTypeArgs)))
{
args = args ?? Tools.Empty();
var pars = m.GetParameters();
if (args.Count == pars.Length &&
(args.Count == 0 || AreArgExpressionsAndParamsOfTheSameType(args, pars)))
return m;
}
}
}
return type.GetTypeInfo().BaseType?.FindMethod(methodName, typeArgs, args, isStatic);
}
private static bool AreTypesTheSame(Type[] source, Type[] target)
{
for (var i = 0; i < source.Length; i++)
if (source[i] != target[i])
return false;
return true;
}
private static bool AreArgExpressionsAndParamsOfTheSameType(IReadOnlyList args, ParameterInfo[] pars)
{
for (var i = 0; i < pars.Length; i++)
if (pars[i].ParameterType != args[i].Type)
return false;
return true;
}
public static IReadOnlyList AsReadOnlyList(this IEnumerable xs)
{
if (xs is IReadOnlyList list)
return list;
return xs == null ? null : new List(xs);
}
internal static bool IsImplicitlyNumericConvertibleTo(this Type source, Type target)
{
if (source == typeof(Char))
return
target == typeof(UInt16) ||
target == typeof(Int32) ||
target == typeof(UInt32) ||
target == typeof(Int64) ||
target == typeof(UInt64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(SByte))
return
target == typeof(Int16) ||
target == typeof(Int32) ||
target == typeof(Int64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(Byte))
return
target == typeof(Int16) ||
target == typeof(UInt16) ||
target == typeof(Int32) ||
target == typeof(UInt32) ||
target == typeof(Int64) ||
target == typeof(UInt64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(Int16))
return
target == typeof(Int32) ||
target == typeof(Int64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(UInt16))
return
target == typeof(Int32) ||
target == typeof(UInt32) ||
target == typeof(Int64) ||
target == typeof(UInt64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(Int32))
return
target == typeof(Int64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(UInt32))
return
target == typeof(UInt32) ||
target == typeof(UInt64) ||
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(Int64) ||
source == typeof(UInt64))
return
target == typeof(Single) ||
target == typeof(Double) ||
target == typeof(Decimal);
if (source == typeof(Single))
return target == typeof(Double);
return false;
}
}
/// Converts the object of known type into the valid C# code representation
public static class CodePrinter
{
/// Replace with yours if needed
public static Func GetTypeNameDefault = t => t.Name;
/// Converts the `typeof()` into the proper C# representation.
public static string ToCode(this Type type, Func getTypeName = null) =>
type == null ? "null" : $"typeof({type.ToTypeCode()})";
/// Converts the into the proper C# representation.
public static string ToTypeCode(this Type type, Func getTypeName = null)
{
var isArray = type.IsArray;
if (isArray)
type = type.GetElementType();
var typeName = (getTypeName ?? GetTypeNameDefault)(type);
var typeInfo = type.GetTypeInfo();
if (!typeInfo.IsGenericType)
return typeName.Replace('+', '.');
var s = new StringBuilder(typeName.Substring(0, typeName.IndexOf('`')).Replace('+', '.'));
s.Append('<');
var genericArgs = typeInfo.GetGenericTypeParametersOrArguments();
if (typeInfo.IsGenericTypeDefinition)
s.Append(',', genericArgs.Length - 1);
else
{
for (var i = 0; i < genericArgs.Length; i++)
{
if (i > 0)
s.Append(", ");
s.Append(genericArgs[i].ToTypeCode(getTypeName));
}
}
s.Append('>');
if (isArray)
s.Append("[]");
return s.ToString();
}
/// Prints valid C# Boolean
public static string ToCode(this bool x) => x ? "true" : "false";
/// Prints valid C# String escaping the things
public static string ToCode(this string x) =>
x == null ? "null"
: $"\"{x.Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n")}\"";
/// Prints valid c# Enum literal
public static string ToEnumValueCode(this Type enumType, object x)
{
var enumTypeInfo = enumType.GetTypeInfo();
if (enumTypeInfo.IsGenericType && enumTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (x == null)
return "null";
enumType = GetGenericTypeParametersOrArguments(enumTypeInfo)[0];
}
return $"{enumType.ToTypeCode()}.{Enum.GetName(enumType, x)}";
}
private static Type[] GetGenericTypeParametersOrArguments(this TypeInfo typeInfo) =>
typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters : typeInfo.GenericTypeArguments;
/// Prints many code items as array initializer.
public static string ToCommaSeparatedCode(this IEnumerable items, Func