1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Microsoft Public License. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Microsoft Public License, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Microsoft Public License.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Reflection;
22 using System.Reflection.Emit;
23 using System.Threading;
24 using System.Runtime.CompilerServices;
31 namespace Microsoft.Scripting.Ast {
33 namespace System.Linq.Expressions {
38 /// Creates a <see cref="LambdaExpression"/> node.
39 /// This captures a block of code that is similar to a .NET method body.
42 /// Lambda expressions take input through parameters and are expected to be fully bound.
45 [DebuggerTypeProxy(typeof(Expression.LambdaExpressionProxy))]
47 public abstract class LambdaExpression : Expression {
48 private readonly string _name;
49 private readonly Expression _body;
50 private readonly ReadOnlyCollection<ParameterExpression> _parameters;
51 private readonly Type _delegateType;
52 private readonly bool _tailCall;
54 internal LambdaExpression(
59 ReadOnlyCollection<ParameterExpression> parameters
62 Debug.Assert(delegateType != null);
66 _parameters = parameters;
67 _delegateType = delegateType;
72 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
74 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
75 public sealed override Type Type {
76 get { return _delegateType; }
80 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
82 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
83 public sealed override ExpressionType NodeType {
84 get { return ExpressionType.Lambda; }
88 /// Gets the parameters of the lambda expression.
90 public ReadOnlyCollection<ParameterExpression> Parameters {
91 get { return _parameters; }
95 /// Gets the name of the lambda expression.
97 /// <remarks>Used for debugging purposes.</remarks>
103 /// Gets the body of the lambda expression.
105 public Expression Body {
106 get { return _body; }
110 /// Gets the return type of the lambda expression.
112 public Type ReturnType {
113 get { return Type.GetMethod("Invoke").ReturnType; }
117 /// Gets the value that indicates if the lambda expression will be compiled with
118 /// tail call optimization.
120 public bool TailCall {
121 get { return _tailCall; }
125 /// Produces a delegate that represents the lambda expression.
127 /// <returns>A delegate containing the compiled version of the lambda.</returns>
128 public Delegate Compile() {
129 return LambdaCompiler.Compile(this, null);
133 /// Produces a delegate that represents the lambda expression.
135 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
136 /// <returns>A delegate containing the compiled version of the lambda.</returns>
137 public Delegate Compile(DebugInfoGenerator debugInfoGenerator) {
138 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
139 return LambdaCompiler.Compile(this, debugInfoGenerator);
143 /// Compiles the lambda into a method definition.
145 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
146 public void CompileToMethod(MethodBuilder method) {
147 CompileToMethodInternal(method, null);
151 /// Compiles the lambda into a method definition and custom debug information.
153 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
154 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
155 public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
156 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
157 CompileToMethodInternal(method, debugInfoGenerator);
160 private void CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
161 ContractUtils.RequiresNotNull(method, "method");
162 ContractUtils.Requires(method.IsStatic, "method");
163 var type = method.DeclaringType as TypeBuilder;
164 if (type == null) throw Error.MethodBuilderDoesNotHaveTypeBuilder();
166 LambdaCompiler.Compile(this, method, debugInfoGenerator);
169 internal abstract LambdaExpression Accept(StackSpiller spiller);
173 /// Defines a <see cref="Expression{TDelegate}"/> node.
174 /// This captures a block of code that is similar to a .NET method body.
176 /// <typeparam name="TDelegate">The type of the delegate.</typeparam>
178 /// Lambda expressions take input through parameters and are expected to be fully bound.
180 public sealed class Expression<TDelegate> : LambdaExpression {
181 internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
182 : base(typeof(TDelegate), name, body, tailCall, parameters) {
186 /// Produces a delegate that represents the lambda expression.
188 /// <returns>A delegate containing the compiled version of the lambda.</returns>
189 public new TDelegate Compile() {
190 return (TDelegate)(object)LambdaCompiler.Compile(this, null);
194 /// Produces a delegate that represents the lambda expression.
196 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
197 /// <returns>A delegate containing the compiled version of the lambda.</returns>
198 public new TDelegate Compile(DebugInfoGenerator debugInfoGenerator) {
199 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
200 return (TDelegate)(object)LambdaCompiler.Compile(this, debugInfoGenerator);
204 /// Creates a new expression that is like this one, but using the
205 /// supplied children. If all of the children are the same, it will
206 /// return this expression.
208 /// <param name="body">The <see cref="LambdaExpression.Body">Body</see> property of the result.</param>
209 /// <param name="parameters">The <see cref="LambdaExpression.Parameters">Parameters</see> property of the result.</param>
210 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
211 public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters) {
212 if (body == Body && parameters == Parameters) {
215 return Expression.Lambda<TDelegate>(body, Name, TailCall, parameters);
219 /// Dispatches to the specific visit method for this node type.
221 protected internal override Expression Accept(ExpressionVisitor visitor) {
222 return visitor.VisitLambda(this);
225 internal override LambdaExpression Accept(StackSpiller spiller) {
226 return spiller.Rewrite(this);
229 internal static LambdaExpression Create(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
230 return new Expression<TDelegate>(body, name, tailCall, parameters);
235 public partial class Expression {
238 /// Creates an Expression{T} given the delegate type. Caches the
239 /// factory method to speed up repeated creations for the same T.
241 internal static LambdaExpression CreateLambda(Type delegateType, Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
242 // Get or create a delegate to the public Expression.Lambda<T>
243 // method and call that will be used for creating instances of this
245 LambdaFactory fastPath;
246 if (_LambdaFactories == null) {
247 // NOTE: this must be Interlocked assigment since we use _LambdaFactories for locking.
248 Interlocked.CompareExchange(ref _LambdaFactories, new CacheDict<Type, LambdaFactory>(50), null);
251 MethodInfo create = null;
252 lock (_LambdaFactories) {
253 if (!_LambdaFactories.TryGetValue(delegateType, out fastPath)) {
254 create = typeof(Expression<>).MakeGenericType(delegateType).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
255 if (TypeUtils.CanCache(delegateType)) {
256 _LambdaFactories[delegateType] = fastPath = (LambdaFactory)Delegate.CreateDelegate(typeof(LambdaFactory), create);
261 if (fastPath != null) {
262 return fastPath(body, name, tailCall, parameters);
265 Debug.Assert(create != null);
266 return (LambdaExpression)create.Invoke(null, new object[] { body, name, tailCall, parameters });
270 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
272 /// <typeparam name="TDelegate">The delegate type. </typeparam>
273 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
274 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
275 /// <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>
276 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) {
277 return Lambda<TDelegate>(body, false, (IEnumerable<ParameterExpression>)parameters);
281 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
283 /// <typeparam name="TDelegate">The delegate type. </typeparam>
284 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
285 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
286 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
287 /// <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>
288 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, params ParameterExpression[] parameters) {
289 return Lambda<TDelegate>(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
293 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
295 /// <typeparam name="TDelegate">The delegate type. </typeparam>
296 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
297 /// <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>
298 /// <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>
299 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, IEnumerable<ParameterExpression> parameters) {
300 return Lambda<TDelegate>(body, null, false, parameters);
304 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
306 /// <typeparam name="TDelegate">The delegate type. </typeparam>
307 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
308 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
309 /// <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>
310 /// <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>
311 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
312 return Lambda<TDelegate>(body, null, tailCall, parameters);
316 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
318 /// <typeparam name="TDelegate">The delegate type. </typeparam>
319 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
320 /// <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>
321 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
322 /// <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>
323 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, IEnumerable<ParameterExpression> parameters) {
324 return Lambda<TDelegate>(body, name, false, parameters);
328 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
330 /// <typeparam name="TDelegate">The delegate type. </typeparam>
331 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
332 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
333 /// <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>
334 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
335 /// <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>
336 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
337 var parameterList = parameters.ToReadOnly();
338 ValidateLambdaArgs(typeof(TDelegate), ref body, parameterList);
339 return new Expression<TDelegate>(body, name, tailCall, parameterList);
344 /// Creates a LambdaExpression by first constructing a delegate type.
346 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
347 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
348 /// <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>
349 public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters) {
350 return Lambda(body, false, (IEnumerable<ParameterExpression>)parameters);
354 /// Creates a LambdaExpression by first constructing a delegate type.
356 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
357 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
358 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
359 /// <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>
360 public static LambdaExpression Lambda(Expression body, bool tailCall, params ParameterExpression[] parameters) {
361 return Lambda(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
365 /// Creates a LambdaExpression by first constructing a delegate type.
367 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
368 /// <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>
369 /// <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>
370 public static LambdaExpression Lambda(Expression body, IEnumerable<ParameterExpression> parameters) {
371 return Lambda(body, null, false, parameters);
375 /// Creates a LambdaExpression by first constructing a delegate type.
377 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
378 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
379 /// <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>
380 /// <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>
381 public static LambdaExpression Lambda(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
382 return Lambda(body, null, tailCall, parameters);
386 /// Creates a LambdaExpression by first constructing a delegate type.
388 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
389 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
390 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
391 /// <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>
392 public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) {
393 return Lambda(delegateType, body, null, false, parameters);
397 /// Creates a LambdaExpression by first constructing a delegate type.
399 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
400 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
401 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
402 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
403 /// <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>
404 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, params ParameterExpression[] parameters) {
405 return Lambda(delegateType, body, null, tailCall, parameters);
409 /// Creates a LambdaExpression by first constructing a delegate type.
411 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
412 /// <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>
413 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
414 /// <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>
415 public static LambdaExpression Lambda(Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters) {
416 return Lambda(delegateType, body, null, false, parameters);
420 /// Creates a LambdaExpression by first constructing a delegate type.
422 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
423 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
424 /// <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>
425 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
426 /// <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>
427 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
428 return Lambda(delegateType, body, null, tailCall, parameters);
432 /// Creates a LambdaExpression by first constructing a delegate type.
434 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
435 /// <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>
436 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
437 /// <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>
438 public static LambdaExpression Lambda(Expression body, string name, IEnumerable<ParameterExpression> parameters) {
439 return Lambda(body, name, false, parameters);
443 /// Creates a LambdaExpression by first constructing a delegate type.
445 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
446 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
447 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
448 /// <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>
449 /// <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>
450 public static LambdaExpression Lambda(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
451 ContractUtils.RequiresNotNull(body, "body");
453 var parameterList = parameters.ToReadOnly();
455 int paramCount = parameterList.Count;
456 Type[] typeArgs = new Type[paramCount + 1];
457 if (paramCount > 0) {
458 var set = new Set<ParameterExpression>(parameterList.Count);
459 for (int i = 0; i < paramCount; i++) {
460 var param = parameterList[i];
461 ContractUtils.RequiresNotNull(param, "parameter");
462 typeArgs[i] = param.IsByRef ? param.Type.MakeByRefType() : param.Type;
463 if (set.Contains(param)) {
464 throw Error.DuplicateVariable(param);
469 typeArgs[paramCount] = body.Type;
471 Type delegateType = DelegateHelpers.MakeDelegateType(typeArgs);
473 return CreateLambda(delegateType, body, name, tailCall, parameterList);
477 /// Creates a LambdaExpression by first constructing a delegate type.
479 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
480 /// <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>
481 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
482 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
483 /// <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>
484 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, IEnumerable<ParameterExpression> parameters) {
485 var paramList = parameters.ToReadOnly();
486 ValidateLambdaArgs(delegateType, ref body, paramList);
488 return CreateLambda(delegateType, body, name, false, paramList);
492 /// Creates a LambdaExpression by first constructing a delegate type.
494 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
495 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
496 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
497 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
498 /// <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>
499 /// <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>
500 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
501 var paramList = parameters.ToReadOnly();
502 ValidateLambdaArgs(delegateType, ref body, paramList);
504 return CreateLambda(delegateType, body, name, tailCall, paramList);
507 private static void ValidateLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection<ParameterExpression> parameters) {
508 ContractUtils.RequiresNotNull(delegateType, "delegateType");
509 RequiresCanRead(body, "body");
511 if (!typeof(Delegate).IsAssignableFrom(delegateType) || delegateType == typeof(Delegate)) {
512 throw Error.LambdaTypeMustBeDerivedFromSystemDelegate();
516 lock (_LambdaDelegateCache) {
517 if (!_LambdaDelegateCache.TryGetValue(delegateType, out mi)) {
518 mi = delegateType.GetMethod("Invoke");
519 if (TypeUtils.CanCache(delegateType)) {
520 _LambdaDelegateCache[delegateType] = mi;
525 ParameterInfo[] pis = mi.GetParametersCached();
527 if (pis.Length > 0) {
528 if (pis.Length != parameters.Count) {
529 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
531 var set = new Set<ParameterExpression>(pis.Length);
532 for (int i = 0, n = pis.Length; i < n; i++) {
533 ParameterExpression pex = parameters[i];
534 ParameterInfo pi = pis[i];
535 RequiresCanRead(pex, "parameters");
536 Type pType = pi.ParameterType;
538 if (!pType.IsByRef) {
539 //We cannot pass a parameter of T& to a delegate that takes T or any non-ByRef type.
540 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type.MakeByRefType(), pType);
542 pType = pType.GetElementType();
544 if (!TypeUtils.AreReferenceAssignable(pex.Type, pType)) {
545 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type, pType);
547 if (set.Contains(pex)) {
548 throw Error.DuplicateVariable(pex);
552 } else if (parameters.Count > 0) {
553 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
555 if (mi.ReturnType != typeof(void) && !TypeUtils.AreReferenceAssignable(mi.ReturnType, body.Type)) {
556 if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), mi.ReturnType) && mi.ReturnType.IsAssignableFrom(body.GetType())) {
557 body = Expression.Quote(body);
559 throw Error.ExpressionTypeDoesNotMatchReturn(body.Type, mi.ReturnType);
564 private static bool ValidateTryGetFuncActionArgs(Type[] typeArgs) {
565 if (typeArgs == null) {
566 throw new ArgumentNullException("typeArgs");
568 for (int i = 0, n = typeArgs.Length; i < n; i++) {
571 throw new ArgumentNullException("typeArgs");
581 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
582 /// The last type argument specifies the return type of the created delegate.
584 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
585 /// <returns>The type of a System.Func delegate that has the specified type arguments.</returns>
586 public static Type GetFuncType(params Type[] typeArgs) {
587 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
589 Type result = DelegateHelpers.GetFuncType(typeArgs);
590 if (result == null) {
591 throw Error.IncorrectNumberOfTypeArgsForFunc();
597 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
598 /// The last type argument specifies the return type of the created delegate.
600 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
601 /// <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>
602 /// <returns>true if generic System.Func delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
603 public static bool TryGetFuncType(Type[] typeArgs, out Type funcType) {
604 if (ValidateTryGetFuncActionArgs(typeArgs)) {
605 return (funcType = DelegateHelpers.GetFuncType(typeArgs)) != null;
612 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
614 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
615 /// <returns>The type of a System.Action delegate that has the specified type arguments.</returns>
616 public static Type GetActionType(params Type[] typeArgs) {
617 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
619 Type result = DelegateHelpers.GetActionType(typeArgs);
620 if (result == null) {
621 throw Error.IncorrectNumberOfTypeArgsForAction();
627 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
629 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
630 /// <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>
631 /// <returns>true if generic System.Action delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
632 public static bool TryGetActionType(Type[] typeArgs, out Type actionType) {
633 if (ValidateTryGetFuncActionArgs(typeArgs)) {
634 return (actionType = DelegateHelpers.GetActionType(typeArgs)) != null;
641 /// Gets a <see cref="Type"/> object that represents a generic System.Func or System.Action delegate type that has specific type arguments.
642 /// The last type argument determines the return type of the delegate. If no Func or Action is large enough, it will generate a custom
645 /// <param name="typeArgs">The type arguments of the delegate.</param>
646 /// <returns>The delegate type.</returns>
648 /// As with Func, the last argument is the return type. It can be set
649 /// to System.Void to produce an Action.</remarks>
650 public static Type GetDelegateType(params Type[] typeArgs) {
651 ContractUtils.RequiresNotEmpty(typeArgs, "typeArgs");
652 ContractUtils.RequiresNotNullItems(typeArgs, "typeArgs");
653 return DelegateHelpers.MakeDelegateType(typeArgs);