1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. 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 Apache License, Version 2.0, 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 Apache License, Version 2.0.
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;
23 using System.Reflection.Emit;
25 using System.Threading;
26 using System.Runtime.CompilerServices;
29 namespace Microsoft.Scripting.Ast {
31 namespace System.Linq.Expressions {
36 /// Creates a <see cref="LambdaExpression"/> node.
37 /// This captures a block of code that is similar to a .NET method body.
40 /// Lambda expressions take input through parameters and are expected to be fully bound.
42 [DebuggerTypeProxy(typeof(Expression.LambdaExpressionProxy))]
43 public abstract class LambdaExpression : Expression {
44 private readonly string _name;
45 private readonly Expression _body;
46 private readonly ReadOnlyCollection<ParameterExpression> _parameters;
47 private readonly Type _delegateType;
48 private readonly bool _tailCall;
50 internal LambdaExpression(
55 ReadOnlyCollection<ParameterExpression> parameters
58 Debug.Assert(delegateType != null);
62 _parameters = parameters;
63 _delegateType = delegateType;
67 internal abstract LambdaExpression Accept(StackSpiller spiller);
70 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
72 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
73 public sealed override Type Type {
74 get { return _delegateType; }
78 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
80 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
81 public sealed override ExpressionType NodeType {
82 get { return ExpressionType.Lambda; }
86 /// Gets the parameters of the lambda expression.
88 public ReadOnlyCollection<ParameterExpression> Parameters {
89 get { return _parameters; }
93 /// Gets the name of the lambda expression.
95 /// <remarks>Used for debugging purposes.</remarks>
101 /// Gets the body of the lambda expression.
103 public Expression Body {
104 get { return _body; }
108 /// Gets the return type of the lambda expression.
110 public Type ReturnType {
111 get { return Type.GetMethod("Invoke").ReturnType; }
115 /// Gets the value that indicates if the lambda expression will be compiled with
116 /// tail call optimization.
118 public bool TailCall {
119 get { return _tailCall; }
123 /// Produces a delegate that represents the lambda expression.
125 /// <returns>A delegate containing the compiled version of the lambda.</returns>
126 public Delegate Compile() {
127 return LambdaCompiler.Compile(this, null);
131 /// Produces a delegate that represents the lambda expression.
133 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
134 /// <returns>A delegate containing the compiled version of the lambda.</returns>
135 public Delegate Compile(DebugInfoGenerator debugInfoGenerator) {
136 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
137 return LambdaCompiler.Compile(this, debugInfoGenerator);
142 /// Compiles the lambda into a method definition.
144 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
145 public void CompileToMethod(MethodBuilder method) {
146 CompileToMethodInternal(method, null);
150 /// Compiles the lambda into a method definition and custom debug information.
152 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
153 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
154 public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
155 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
156 CompileToMethodInternal(method, debugInfoGenerator);
159 private void CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
160 ContractUtils.RequiresNotNull(method, "method");
161 ContractUtils.Requires(method.IsStatic, "method");
162 var type = method.DeclaringType as TypeBuilder;
163 if (type == null) throw Error.MethodBuilderDoesNotHaveTypeBuilder();
165 LambdaCompiler.Compile(this, method, debugInfoGenerator);
171 /// Defines a <see cref="Expression{TDelegate}"/> node.
172 /// This captures a block of code that is similar to a .NET method body.
174 /// <typeparam name="TDelegate">The type of the delegate.</typeparam>
176 /// Lambda expressions take input through parameters and are expected to be fully bound.
178 public sealed class Expression<TDelegate> : LambdaExpression {
179 internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
180 : base(typeof(TDelegate), name, body, tailCall, parameters) {
184 /// Produces a delegate that represents the lambda expression.
186 /// <returns>A delegate containing the compiled version of the lambda.</returns>
187 public new TDelegate Compile() {
188 return (TDelegate)(object)LambdaCompiler.Compile(this, null);
192 /// Produces a delegate that represents the lambda expression.
194 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
195 /// <returns>A delegate containing the compiled version of the lambda.</returns>
196 public new TDelegate Compile(DebugInfoGenerator debugInfoGenerator) {
197 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
198 return (TDelegate)(object)LambdaCompiler.Compile(this, debugInfoGenerator);
202 /// Creates a new expression that is like this one, but using the
203 /// supplied children. If all of the children are the same, it will
204 /// return this expression.
206 /// <param name="body">The <see cref="LambdaExpression.Body">Body</see> property of the result.</param>
207 /// <param name="parameters">The <see cref="LambdaExpression.Parameters">Parameters</see> property of the result.</param>
208 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
209 public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters) {
210 if (body == Body && parameters == Parameters) {
213 return Expression.Lambda<TDelegate>(body, Name, TailCall, parameters);
217 /// Dispatches to the specific visit method for this node type.
219 protected internal override Expression Accept(ExpressionVisitor visitor) {
220 return visitor.VisitLambda(this);
223 internal override LambdaExpression Accept(StackSpiller spiller) {
224 return spiller.Rewrite(this);
227 internal static LambdaExpression Create(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
228 return new Expression<TDelegate>(body, name, tailCall, parameters);
233 public partial class Expression {
236 /// Creates an Expression{T} given the delegate type. Caches the
237 /// factory method to speed up repeated creations for the same T.
239 internal static LambdaExpression CreateLambda(Type delegateType, Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
240 // Get or create a delegate to the public Expression.Lambda<T>
241 // method and call that will be used for creating instances of this
243 LambdaFactory fastPath;
244 if (_LambdaFactories == null) {
245 // NOTE: this must be Interlocked assigment since we use _LambdaFactories for locking.
246 Interlocked.CompareExchange(ref _LambdaFactories, new CacheDict<Type, LambdaFactory>(50), null);
249 MethodInfo create = null;
250 lock (_LambdaFactories) {
251 if (!_LambdaFactories.TryGetValue(delegateType, out fastPath)) {
252 create = typeof(Expression<>).MakeGenericType(delegateType).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
253 if (TypeUtils.CanCache(delegateType)) {
254 _LambdaFactories[delegateType] = fastPath = (LambdaFactory)Delegate.CreateDelegate(typeof(LambdaFactory), create);
259 if (fastPath != null) {
260 return fastPath(body, name, tailCall, parameters);
263 Debug.Assert(create != null);
264 return (LambdaExpression)create.Invoke(null, new object[] { body, name, tailCall, parameters });
268 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
270 /// <typeparam name="TDelegate">The delegate type. </typeparam>
271 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
272 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
273 /// <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>
274 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) {
275 return Lambda<TDelegate>(body, false, (IEnumerable<ParameterExpression>)parameters);
279 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
281 /// <typeparam name="TDelegate">The delegate type. </typeparam>
282 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
283 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
284 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
285 /// <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>
286 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, params ParameterExpression[] parameters) {
287 return Lambda<TDelegate>(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
291 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
293 /// <typeparam name="TDelegate">The delegate type. </typeparam>
294 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
295 /// <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>
296 /// <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>
297 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, IEnumerable<ParameterExpression> parameters) {
298 return Lambda<TDelegate>(body, null, false, parameters);
302 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
304 /// <typeparam name="TDelegate">The delegate type. </typeparam>
305 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
306 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
307 /// <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>
308 /// <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>
309 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
310 return Lambda<TDelegate>(body, null, tailCall, parameters);
314 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
316 /// <typeparam name="TDelegate">The delegate type. </typeparam>
317 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
318 /// <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>
319 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
320 /// <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>
321 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, IEnumerable<ParameterExpression> parameters) {
322 return Lambda<TDelegate>(body, name, false, parameters);
326 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
328 /// <typeparam name="TDelegate">The delegate type. </typeparam>
329 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
330 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
331 /// <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>
332 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
333 /// <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>
334 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
335 var parameterList = parameters.ToReadOnly();
336 ValidateLambdaArgs(typeof(TDelegate), ref body, parameterList);
337 return new Expression<TDelegate>(body, name, tailCall, parameterList);
342 /// Creates a LambdaExpression by first constructing a delegate type.
344 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
345 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
346 /// <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>
347 public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters) {
348 return Lambda(body, false, (IEnumerable<ParameterExpression>)parameters);
352 /// Creates a LambdaExpression by first constructing a delegate type.
354 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
355 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
356 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
357 /// <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>
358 public static LambdaExpression Lambda(Expression body, bool tailCall, params ParameterExpression[] parameters) {
359 return Lambda(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
363 /// Creates a LambdaExpression by first constructing a delegate type.
365 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
366 /// <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>
367 /// <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>
368 public static LambdaExpression Lambda(Expression body, IEnumerable<ParameterExpression> parameters) {
369 return Lambda(body, null, false, parameters);
373 /// Creates a LambdaExpression by first constructing a delegate type.
375 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
376 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
377 /// <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>
378 /// <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>
379 public static LambdaExpression Lambda(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
380 return Lambda(body, null, tailCall, parameters);
384 /// Creates a LambdaExpression by first constructing a delegate type.
386 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
387 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
388 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
389 /// <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>
390 public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) {
391 return Lambda(delegateType, body, null, false, parameters);
395 /// Creates a LambdaExpression by first constructing a delegate type.
397 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
398 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
399 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
400 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
401 /// <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>
402 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, params ParameterExpression[] parameters) {
403 return Lambda(delegateType, body, null, tailCall, parameters);
407 /// Creates a LambdaExpression by first constructing a delegate type.
409 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
410 /// <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>
411 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
412 /// <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>
413 public static LambdaExpression Lambda(Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters) {
414 return Lambda(delegateType, body, null, false, parameters);
418 /// Creates a LambdaExpression by first constructing a delegate type.
420 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
421 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
422 /// <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>
423 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
424 /// <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>
425 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
426 return Lambda(delegateType, body, null, tailCall, parameters);
430 /// Creates a LambdaExpression by first constructing a delegate type.
432 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
433 /// <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>
434 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
435 /// <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>
436 public static LambdaExpression Lambda(Expression body, string name, IEnumerable<ParameterExpression> parameters) {
437 return Lambda(body, name, false, parameters);
441 /// Creates a LambdaExpression by first constructing a delegate type.
443 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
444 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
445 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
446 /// <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>
447 /// <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>
448 public static LambdaExpression Lambda(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
449 ContractUtils.RequiresNotNull(body, "body");
451 var parameterList = parameters.ToReadOnly();
453 int paramCount = parameterList.Count;
454 Type[] typeArgs = new Type[paramCount + 1];
455 if (paramCount > 0) {
456 var set = new Set<ParameterExpression>(parameterList.Count);
457 for (int i = 0; i < paramCount; i++) {
458 var param = parameterList[i];
459 ContractUtils.RequiresNotNull(param, "parameter");
460 typeArgs[i] = param.IsByRef ? param.Type.MakeByRefType() : param.Type;
461 if (set.Contains(param)) {
462 throw Error.DuplicateVariable(param);
467 typeArgs[paramCount] = body.Type;
469 Type delegateType = DelegateHelpers.MakeDelegateType(typeArgs);
471 return CreateLambda(delegateType, body, name, tailCall, parameterList);
475 /// Creates a LambdaExpression by first constructing a delegate type.
477 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
478 /// <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>
479 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
480 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
481 /// <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>
482 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, IEnumerable<ParameterExpression> parameters) {
483 var paramList = parameters.ToReadOnly();
484 ValidateLambdaArgs(delegateType, ref body, paramList);
486 return CreateLambda(delegateType, body, name, false, paramList);
490 /// Creates a LambdaExpression by first constructing a delegate type.
492 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
493 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
494 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
495 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
496 /// <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>
497 /// <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>
498 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
499 var paramList = parameters.ToReadOnly();
500 ValidateLambdaArgs(delegateType, ref body, paramList);
502 return CreateLambda(delegateType, body, name, tailCall, paramList);
505 private static void ValidateLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection<ParameterExpression> parameters) {
506 ContractUtils.RequiresNotNull(delegateType, "delegateType");
507 RequiresCanRead(body, "body");
509 if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType) || delegateType == typeof(MulticastDelegate)) {
510 throw Error.LambdaTypeMustBeDerivedFromSystemDelegate();
514 lock (_LambdaDelegateCache) {
515 if (!_LambdaDelegateCache.TryGetValue(delegateType, out mi)) {
516 mi = delegateType.GetMethod("Invoke");
517 if (TypeUtils.CanCache(delegateType)) {
518 _LambdaDelegateCache[delegateType] = mi;
523 ParameterInfo[] pis = mi.GetParametersCached();
525 if (pis.Length > 0) {
526 if (pis.Length != parameters.Count) {
527 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
529 var set = new Set<ParameterExpression>(pis.Length);
530 for (int i = 0, n = pis.Length; i < n; i++) {
531 ParameterExpression pex = parameters[i];
532 ParameterInfo pi = pis[i];
533 RequiresCanRead(pex, "parameters");
534 Type pType = pi.ParameterType;
536 if (!pType.IsByRef) {
537 //We cannot pass a parameter of T& to a delegate that takes T or any non-ByRef type.
538 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type.MakeByRefType(), pType);
540 pType = pType.GetElementType();
542 if (!TypeUtils.AreReferenceAssignable(pex.Type, pType)) {
543 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type, pType);
545 if (set.Contains(pex)) {
546 throw Error.DuplicateVariable(pex);
550 } else if (parameters.Count > 0) {
551 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
553 if (mi.ReturnType != typeof(void) && !TypeUtils.AreReferenceAssignable(mi.ReturnType, body.Type)) {
554 if (!TryQuote(mi.ReturnType, ref body)) {
555 throw Error.ExpressionTypeDoesNotMatchReturn(body.Type, mi.ReturnType);
560 private static bool ValidateTryGetFuncActionArgs(Type[] typeArgs) {
561 if (typeArgs == null) {
562 throw new ArgumentNullException("typeArgs");
564 for (int i = 0, n = typeArgs.Length; i < n; i++) {
567 throw new ArgumentNullException("typeArgs");
577 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
578 /// The last type argument specifies the return type of the created delegate.
580 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
581 /// <returns>The type of a System.Func delegate that has the specified type arguments.</returns>
582 public static Type GetFuncType(params Type[] typeArgs) {
583 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
585 Type result = DelegateHelpers.GetFuncType(typeArgs);
586 if (result == null) {
587 throw Error.IncorrectNumberOfTypeArgsForFunc();
593 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
594 /// The last type argument specifies the return type of the created delegate.
596 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
597 /// <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>
598 /// <returns>true if generic System.Func delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
599 public static bool TryGetFuncType(Type[] typeArgs, out Type funcType) {
600 if (ValidateTryGetFuncActionArgs(typeArgs)) {
601 return (funcType = DelegateHelpers.GetFuncType(typeArgs)) != null;
608 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
610 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
611 /// <returns>The type of a System.Action delegate that has the specified type arguments.</returns>
612 public static Type GetActionType(params Type[] typeArgs) {
613 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
615 Type result = DelegateHelpers.GetActionType(typeArgs);
616 if (result == null) {
617 throw Error.IncorrectNumberOfTypeArgsForAction();
623 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
625 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
626 /// <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>
627 /// <returns>true if generic System.Action delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
628 public static bool TryGetActionType(Type[] typeArgs, out Type actionType) {
629 if (ValidateTryGetFuncActionArgs(typeArgs)) {
630 return (actionType = DelegateHelpers.GetActionType(typeArgs)) != null;
637 /// Gets a <see cref="Type"/> object that represents a generic System.Func or System.Action delegate type that has specific type arguments.
638 /// The last type argument determines the return type of the delegate. If no Func or Action is large enough, it will generate a custom
641 /// <param name="typeArgs">The type arguments of the delegate.</param>
642 /// <returns>The delegate type.</returns>
644 /// As with Func, the last argument is the return type. It can be set
645 /// to System.Void to produce an Action.</remarks>
646 public static Type GetDelegateType(params Type[] typeArgs) {
647 ContractUtils.RequiresNotEmpty(typeArgs, "typeArgs");
648 ContractUtils.RequiresNotNullItems(typeArgs, "typeArgs");
649 return DelegateHelpers.MakeDelegateType(typeArgs);