You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
700 lines
38 KiB
700 lines
38 KiB
5 years ago
|
#define FEATURE_CORECLR
|
||
|
#if NET20 || NET30 || !NET_4_6
|
||
|
|
||
|
// Copyright (c) Microsoft. All rights reserved.
|
||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||
|
|
||
|
using System.Collections.Generic;
|
||
|
using System.Collections.ObjectModel;
|
||
|
using System.Diagnostics;
|
||
|
using System.Dynamic.Utils;
|
||
|
using System.Reflection;
|
||
|
using LinqInternal.Collections;
|
||
|
using LinqInternal.Core;
|
||
|
|
||
|
namespace System.Linq.Expressions.Reimplement
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Creates a <see cref="LambdaExpression"/> node.
|
||
|
/// This captures a block of code that is similar to a .NET method body.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Lambda expressions take input through parameters and are expected to be fully bound.
|
||
|
/// </remarks>
|
||
|
[DebuggerTypeProxy(typeof(LambdaExpressionProxy))]
|
||
|
public abstract class LambdaExpression : Expression
|
||
|
{
|
||
|
private readonly string _name;
|
||
|
private readonly Expression _body;
|
||
|
private readonly ReadOnlyCollection<ParameterExpression> _parameters;
|
||
|
private readonly Type _delegateType;
|
||
|
private readonly bool _tailCall;
|
||
|
|
||
|
internal LambdaExpression(
|
||
|
Type delegateType,
|
||
|
string name,
|
||
|
Expression body,
|
||
|
bool tailCall,
|
||
|
ReadOnlyCollection<ParameterExpression> parameters
|
||
|
)
|
||
|
{
|
||
|
Debug.Assert(delegateType != null);
|
||
|
|
||
|
_name = name;
|
||
|
_body = body;
|
||
|
_parameters = parameters;
|
||
|
_delegateType = delegateType;
|
||
|
_tailCall = tailCall;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
|
||
|
/// </summary>
|
||
|
/// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
|
||
|
public sealed override Type Type
|
||
|
{
|
||
|
get { return _delegateType; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
|
||
|
/// </summary>
|
||
|
/// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
|
||
|
public sealed override ExpressionType NodeType
|
||
|
{
|
||
|
get { return ExpressionType.Lambda; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the parameters of the lambda expression.
|
||
|
/// </summary>
|
||
|
public ReadOnlyCollection<ParameterExpression> Parameters
|
||
|
{
|
||
|
get { return _parameters; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the name of the lambda expression.
|
||
|
/// </summary>
|
||
|
/// <remarks>Used for debugging purposes.</remarks>
|
||
|
public string Name
|
||
|
{
|
||
|
get { return _name; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the body of the lambda expression.
|
||
|
/// </summary>
|
||
|
public Expression Body
|
||
|
{
|
||
|
get { return _body; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the return type of the lambda expression.
|
||
|
/// </summary>
|
||
|
public Type ReturnType
|
||
|
{
|
||
|
get { return Type.GetMethod("Invoke").ReturnType; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the value that indicates if the lambda expression will be compiled with
|
||
|
/// tail call optimization.
|
||
|
/// </summary>
|
||
|
public bool TailCall
|
||
|
{
|
||
|
get { return _tailCall; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Produces a delegate that represents the lambda expression.
|
||
|
/// </summary>
|
||
|
/// <returns>A delegate containing the compiled version of the lambda.</returns>
|
||
|
public Delegate Compile()
|
||
|
{
|
||
|
#if FEATURE_CORECLR
|
||
|
return Compiler.LambdaCompiler.Compile(this);
|
||
|
#else
|
||
|
return new System.Linq.Expressions.Interpreter.LightCompiler().CompileTop(this).CreateDelegate();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
protected internal override Expression Accept(ExpressionVisitor visitor)
|
||
|
{
|
||
|
return visitor.VisitLambda(this);
|
||
|
}
|
||
|
|
||
|
public virtual LambdaExpression Update(Expression body, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
if (body == Body && parameters == Parameters)
|
||
|
{
|
||
|
return this;
|
||
|
}
|
||
|
return Lambda(Type, body, Name, TailCall, parameters);
|
||
|
}
|
||
|
|
||
|
#if FEATURE_CORECLR
|
||
|
|
||
|
internal abstract LambdaExpression Accept(Compiler.StackSpiller spiller);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Defines a <see cref="Expression{TDelegate}"/> node.
|
||
|
/// This captures a block of code that is similar to a .NET method body.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The type of the delegate.</typeparam>
|
||
|
/// <remarks>
|
||
|
/// Lambda expressions take input through parameters and are expected to be fully bound.
|
||
|
/// </remarks>
|
||
|
public sealed class Expression<TDelegate> : LambdaExpression
|
||
|
{
|
||
|
public Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
|
||
|
: base(typeof(TDelegate), name, body, tailCall, parameters)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Produces a delegate that represents the lambda expression.
|
||
|
/// </summary>
|
||
|
/// <returns>A delegate containing the compiled version of the lambda.</returns>
|
||
|
public new TDelegate Compile()
|
||
|
{
|
||
|
#if FEATURE_CORECLR
|
||
|
return (TDelegate)(object)Compiler.LambdaCompiler.Compile(this);
|
||
|
#else
|
||
|
return (TDelegate)(object)new System.Linq.Expressions.Interpreter.LightCompiler().CompileTop(this).CreateDelegate();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new expression that is like this one, but using the
|
||
|
/// supplied children. If all of the children are the same, it will
|
||
|
/// return this expression.
|
||
|
/// </summary>
|
||
|
/// <param name="body">The <see cref="LambdaExpression.Body">Body</see> property of the result.</param>
|
||
|
/// <param name="parameters">The <see cref="LambdaExpression.Parameters">Parameters</see> property of the result.</param>
|
||
|
/// <returns>This expression if no children changed, or an expression with the updated children.</returns>
|
||
|
public override LambdaExpression Update(Expression body, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
if (body == Body && parameters == Parameters)
|
||
|
{
|
||
|
return this;
|
||
|
}
|
||
|
return Lambda<TDelegate>(body, Name, TailCall, parameters);
|
||
|
}
|
||
|
|
||
|
protected internal override Expression Accept(ExpressionVisitor visitor)
|
||
|
{
|
||
|
return visitor.VisitLambda(this);
|
||
|
}
|
||
|
|
||
|
#if FEATURE_CORECLR
|
||
|
|
||
|
internal override LambdaExpression Accept(Compiler.StackSpiller spiller)
|
||
|
{
|
||
|
return spiller.Rewrite(this);
|
||
|
}
|
||
|
|
||
|
internal static LambdaExpression Create(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
|
||
|
{
|
||
|
return new Expression<TDelegate>(body, name, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if !FEATURE_CORECLR
|
||
|
// Seperate expression creation class to hide the CreateExpressionFunc function from users reflecting on Expression<T>
|
||
|
public class ExpressionCreator<TDelegate>
|
||
|
{
|
||
|
public static LambdaExpression CreateExpressionFunc(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
|
||
|
{
|
||
|
return new Expression<TDelegate>(body, name, tailCall, parameters);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
public partial class Expression
|
||
|
{
|
||
|
internal static LambdaExpression CreateLambda(Type delegateType, Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
|
||
|
{
|
||
|
// Get or create a delegate to the public Expression.Lambda<T>
|
||
|
// method and call that will be used for creating instances of this
|
||
|
// delegate type
|
||
|
Func<Expression, string, bool, ReadOnlyCollection<ParameterExpression>, LambdaExpression> fastPath;
|
||
|
var factories = _lambdaFactories;
|
||
|
if (factories == null)
|
||
|
{
|
||
|
_lambdaFactories = factories = new CacheDict<Type, Func<Expression, string, bool, ReadOnlyCollection<ParameterExpression>, LambdaExpression>>(50);
|
||
|
}
|
||
|
|
||
|
MethodInfo create = null;
|
||
|
if (!factories.TryGetValue(delegateType, out fastPath))
|
||
|
{
|
||
|
#if FEATURE_CORECLR
|
||
|
create = typeof(Expression<>).MakeGenericType(delegateType).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
|
||
|
#else
|
||
|
create = typeof(ExpressionCreator<>).MakeGenericType(delegateType).GetMethod("CreateExpressionFunc", BindingFlags.Static | BindingFlags.Public);
|
||
|
#endif
|
||
|
if (delegateType.CanCache())
|
||
|
{
|
||
|
factories[delegateType] = fastPath = (Func<Expression, string, bool, ReadOnlyCollection<ParameterExpression>, LambdaExpression>)create.CreateDelegate(typeof(Func<Expression, string, bool, ReadOnlyCollection<ParameterExpression>, LambdaExpression>));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fastPath != null)
|
||
|
{
|
||
|
return fastPath(body, name, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
Debug.Assert(create != null);
|
||
|
return (LambdaExpression)create.Invoke(null, new object[] { body, name, tailCall, parameters });
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda<TDelegate>(body, false, (IEnumerable<ParameterExpression>)parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda<TDelegate>(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda<TDelegate>(body, null, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda<TDelegate>(body, null, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="name">The name of the lambda. Used for generating debugging info.</param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, string name, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda<TDelegate>(body, name, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="TDelegate">The delegate type. </typeparam>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="name">The name of the lambda. Used for generating debugging info.</param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
var parameterList = parameters.ToReadOnly();
|
||
|
ValidateLambdaArgs(typeof(TDelegate), ref body, parameterList);
|
||
|
return new Expression<TDelegate>(body, name, tailCall, parameterList);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda(body, false, (IEnumerable<ParameterExpression>)parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, bool tailCall, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda(body, null, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda(body, null, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda(delegateType, body, null, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, params ParameterExpression[] parameters)
|
||
|
{
|
||
|
return Lambda(delegateType, body, null, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda(delegateType, body, null, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda(delegateType, body, null, tailCall, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="name">The name for the lambda. Used for emitting debug information.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, string name, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
return Lambda(body, name, false, parameters);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="name">The name for the lambda. Used for emitting debug information.</param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
ContractUtils.RequiresNotNull(body, "body");
|
||
|
|
||
|
var parameterList = parameters.ToReadOnly();
|
||
|
|
||
|
var paramCount = parameterList.Count;
|
||
|
var typeArgs = new Type[paramCount + 1];
|
||
|
if (paramCount > 0)
|
||
|
{
|
||
|
var set = new Set<ParameterExpression>(parameterList.Count);
|
||
|
for (var i = 0; i < paramCount; i++)
|
||
|
{
|
||
|
var param = parameterList[i];
|
||
|
ContractUtils.RequiresNotNull(param, "parameter");
|
||
|
typeArgs[i] = param.IsByRef ? param.Type.MakeByRefType() : param.Type;
|
||
|
if (set.Contains(param))
|
||
|
{
|
||
|
throw Error.DuplicateVariable(param);
|
||
|
}
|
||
|
set.Add(param);
|
||
|
}
|
||
|
}
|
||
|
typeArgs[paramCount] = body.Type;
|
||
|
|
||
|
var delegateType = Compiler.DelegateHelpers.MakeDelegateType(typeArgs);
|
||
|
|
||
|
return CreateLambda(delegateType, body, name, tailCall, parameterList);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <param name="name">The name for the lambda. Used for emitting debug information.</param>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, string name, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
var paramList = parameters.ToReadOnly();
|
||
|
ValidateLambdaArgs(delegateType, ref body, paramList);
|
||
|
|
||
|
return CreateLambda(delegateType, body, name, false, paramList);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a LambdaExpression by first constructing a delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
|
||
|
/// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
|
||
|
/// <param name="name">The name for the lambda. Used for emitting debug information.</param>
|
||
|
/// <param name="tailCall">A <see cref="bool"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
|
||
|
/// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
|
||
|
/// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
|
||
|
public static LambdaExpression Lambda(Type delegateType, Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters)
|
||
|
{
|
||
|
var paramList = parameters.ToReadOnly();
|
||
|
ValidateLambdaArgs(delegateType, ref body, paramList);
|
||
|
|
||
|
return CreateLambda(delegateType, body, name, tailCall, paramList);
|
||
|
}
|
||
|
|
||
|
private static void ValidateLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection<ParameterExpression> parameters)
|
||
|
{
|
||
|
ContractUtils.RequiresNotNull(delegateType, "delegateType");
|
||
|
RequiresCanRead(body, "body");
|
||
|
|
||
|
if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType) || delegateType == typeof(MulticastDelegate))
|
||
|
{
|
||
|
throw Error.LambdaTypeMustBeDerivedFromSystemDelegate();
|
||
|
}
|
||
|
|
||
|
MethodInfo mi;
|
||
|
var ldc = _lambdaDelegateCache;
|
||
|
if (!ldc.TryGetValue(delegateType, out mi))
|
||
|
{
|
||
|
mi = delegateType.GetMethod("Invoke");
|
||
|
if (delegateType.CanCache())
|
||
|
{
|
||
|
ldc[delegateType] = mi;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var pis = mi.GetParameters();
|
||
|
|
||
|
if (pis.Length > 0)
|
||
|
{
|
||
|
if (pis.Length != parameters.Count)
|
||
|
{
|
||
|
throw Error.IncorrectNumberOfLambdaDeclarationParameters();
|
||
|
}
|
||
|
var set = new Set<ParameterExpression>(pis.Length);
|
||
|
var n = pis.Length;
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
var pex = parameters[i];
|
||
|
var pi = pis[i];
|
||
|
RequiresCanRead(pex, "parameters");
|
||
|
var pType = pi.ParameterType;
|
||
|
if (pex.IsByRef)
|
||
|
{
|
||
|
if (!pType.IsByRef)
|
||
|
{
|
||
|
//We cannot pass a parameter of T& to a delegate that takes T or any non-ByRef type.
|
||
|
throw Error.ParameterExpressionNotValidAsDelegate(pex.Type.MakeByRefType(), pType);
|
||
|
}
|
||
|
pType = pType.GetElementType();
|
||
|
}
|
||
|
if (!TypeHelper.AreReferenceAssignable(pex.Type, pType))
|
||
|
{
|
||
|
throw Error.ParameterExpressionNotValidAsDelegate(pex.Type, pType);
|
||
|
}
|
||
|
if (set.Contains(pex))
|
||
|
{
|
||
|
throw Error.DuplicateVariable(pex);
|
||
|
}
|
||
|
set.Add(pex);
|
||
|
}
|
||
|
}
|
||
|
else if (parameters.Count > 0)
|
||
|
{
|
||
|
throw Error.IncorrectNumberOfLambdaDeclarationParameters();
|
||
|
}
|
||
|
if (mi.ReturnType != typeof(void) && !TypeHelper.AreReferenceAssignable(mi.ReturnType, body.Type))
|
||
|
{
|
||
|
if (!TryQuote(mi.ReturnType, ref body))
|
||
|
{
|
||
|
throw Error.ExpressionTypeDoesNotMatchReturn(body.Type, mi.ReturnType);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static bool ValidateTryGetFuncActionArgs(Type[] typeArgs)
|
||
|
{
|
||
|
if (typeArgs == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("typeArgs");
|
||
|
}
|
||
|
var n = typeArgs.Length;
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
var a = typeArgs[i];
|
||
|
if (a == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("typeArgs");
|
||
|
}
|
||
|
if (a.IsByRef)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
|
||
|
/// The last type argument specifies the return type of the created delegate.
|
||
|
/// </summary>
|
||
|
/// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
|
||
|
/// <returns>The type of a System.Func delegate that has the specified type arguments.</returns>
|
||
|
public static Type GetFuncType(params Type[] typeArgs)
|
||
|
{
|
||
|
if (!ValidateTryGetFuncActionArgs(typeArgs))
|
||
|
{
|
||
|
throw Error.TypeMustNotBeByRef();
|
||
|
}
|
||
|
|
||
|
var result = Compiler.DelegateHelpers.GetFuncType(typeArgs);
|
||
|
if (result == null)
|
||
|
{
|
||
|
throw Error.IncorrectNumberOfTypeArgsForFunc();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
|
||
|
/// The last type argument specifies the return type of the created delegate.
|
||
|
/// </summary>
|
||
|
/// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
|
||
|
/// <param name="funcType">When this method returns, contains the generic System.Func delegate type that has specific type arguments. Contains null if there is no generic System.Func delegate that matches the <paramref name="typeArgs"/>.This parameter is passed uninitialized.</param>
|
||
|
/// <returns>true if generic System.Func delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
|
||
|
public static bool TryGetFuncType(Type[] typeArgs, out Type funcType)
|
||
|
{
|
||
|
if (ValidateTryGetFuncActionArgs(typeArgs))
|
||
|
{
|
||
|
return (funcType = Compiler.DelegateHelpers.GetFuncType(typeArgs)) != null;
|
||
|
}
|
||
|
funcType = null;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
|
||
|
/// </summary>
|
||
|
/// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
|
||
|
/// <returns>The type of a System.Action delegate that has the specified type arguments.</returns>
|
||
|
public static Type GetActionType(params Type[] typeArgs)
|
||
|
{
|
||
|
if (!ValidateTryGetFuncActionArgs(typeArgs))
|
||
|
{
|
||
|
throw Error.TypeMustNotBeByRef();
|
||
|
}
|
||
|
|
||
|
var result = Compiler.DelegateHelpers.GetActionType(typeArgs);
|
||
|
if (result == null)
|
||
|
{
|
||
|
throw Error.IncorrectNumberOfTypeArgsForAction();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
|
||
|
/// </summary>
|
||
|
/// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
|
||
|
/// <param name="actionType">When this method returns, contains the generic System.Action delegate type that has specific type arguments. Contains null if there is no generic System.Action delegate that matches the <paramref name="typeArgs"/>.This parameter is passed uninitialized.</param>
|
||
|
/// <returns>true if generic System.Action delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
|
||
|
public static bool TryGetActionType(Type[] typeArgs, out Type actionType)
|
||
|
{
|
||
|
if (ValidateTryGetFuncActionArgs(typeArgs))
|
||
|
{
|
||
|
return (actionType = Compiler.DelegateHelpers.GetActionType(typeArgs)) != null;
|
||
|
}
|
||
|
actionType = null;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a <see cref="Type"/> object that represents a generic System.Func or System.Action delegate type that has specific type arguments.
|
||
|
/// The last type argument determines the return type of the delegate. If no Func or Action is large enough, it will generate a custom
|
||
|
/// delegate type.
|
||
|
/// </summary>
|
||
|
/// <param name="typeArgs">The type arguments of the delegate.</param>
|
||
|
/// <returns>The delegate type.</returns>
|
||
|
/// <remarks>
|
||
|
/// As with Func, the last argument is the return type. It can be set
|
||
|
/// to System.Void to produce an Action.</remarks>
|
||
|
public static Type GetDelegateType(params Type[] typeArgs)
|
||
|
{
|
||
|
ContractUtils.RequiresNotEmpty(typeArgs, "typeArgs");
|
||
|
ContractUtils.RequiresNotNullItems(typeArgs, "typeArgs");
|
||
|
return Compiler.DelegateHelpers.MakeDelegateType(typeArgs);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|