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;
22 using System.Reflection.Emit;
23 using System.Threading;
24 using System.Runtime.CompilerServices;
27 namespace Microsoft.Scripting.Ast {
29 namespace System.Linq.Expressions {
34 /// Creates a <see cref="LambdaExpression"/> node.
35 /// This captures a block of code that is similar to a .NET method body.
38 /// Lambda expressions take input through parameters and are expected to be fully bound.
40 [DebuggerTypeProxy(typeof(Expression.LambdaExpressionProxy))]
41 public abstract class LambdaExpression : Expression {
42 private readonly string _name;
43 private readonly Expression _body;
44 private readonly ReadOnlyCollection<ParameterExpression> _parameters;
45 private readonly Type _delegateType;
46 private readonly bool _tailCall;
48 internal LambdaExpression(
53 ReadOnlyCollection<ParameterExpression> parameters
56 Debug.Assert(delegateType != null);
60 _parameters = parameters;
61 _delegateType = delegateType;
65 internal abstract LambdaExpression Accept(StackSpiller spiller);
68 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
70 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
71 public sealed override Type Type {
72 get { return _delegateType; }
76 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
78 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
79 public sealed override ExpressionType NodeType {
80 get { return ExpressionType.Lambda; }
84 /// Gets the parameters of the lambda expression.
86 public ReadOnlyCollection<ParameterExpression> Parameters {
87 get { return _parameters; }
91 /// Gets the name of the lambda expression.
93 /// <remarks>Used for debugging purposes.</remarks>
99 /// Gets the body of the lambda expression.
101 public Expression Body {
102 get { return _body; }
106 /// Gets the return type of the lambda expression.
108 public Type ReturnType {
109 get { return Type.GetMethod("Invoke").ReturnType; }
113 /// Gets the value that indicates if the lambda expression will be compiled with
114 /// tail call optimization.
116 public bool TailCall {
117 get { return _tailCall; }
121 /// Produces a delegate that represents the lambda expression.
123 /// <returns>A delegate containing the compiled version of the lambda.</returns>
124 public Delegate Compile() {
125 return LambdaCompiler.Compile(this, null);
129 /// Produces a delegate that represents the lambda expression.
131 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
132 /// <returns>A delegate containing the compiled version of the lambda.</returns>
133 public Delegate Compile(DebugInfoGenerator debugInfoGenerator) {
134 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
135 return LambdaCompiler.Compile(this, debugInfoGenerator);
140 /// Compiles the lambda into a method definition.
142 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
143 public void CompileToMethod(MethodBuilder method) {
144 CompileToMethodInternal(method, null);
148 /// Compiles the lambda into a method definition and custom debug information.
150 /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
151 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
152 public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
153 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
154 CompileToMethodInternal(method, debugInfoGenerator);
157 private void CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
158 ContractUtils.RequiresNotNull(method, "method");
159 ContractUtils.Requires(method.IsStatic, "method");
160 var type = method.DeclaringType as TypeBuilder;
161 if (type == null) throw Error.MethodBuilderDoesNotHaveTypeBuilder();
163 LambdaCompiler.Compile(this, method, debugInfoGenerator);
169 /// Defines a <see cref="Expression{TDelegate}"/> node.
170 /// This captures a block of code that is similar to a .NET method body.
172 /// <typeparam name="TDelegate">The type of the delegate.</typeparam>
174 /// Lambda expressions take input through parameters and are expected to be fully bound.
176 public sealed class Expression<TDelegate> : LambdaExpression {
177 internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
178 : base(typeof(TDelegate), name, body, tailCall, parameters) {
182 /// Produces a delegate that represents the lambda expression.
184 /// <returns>A delegate containing the compiled version of the lambda.</returns>
185 public new TDelegate Compile() {
186 return (TDelegate)(object)LambdaCompiler.Compile(this, null);
190 /// Produces a delegate that represents the lambda expression.
192 /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
193 /// <returns>A delegate containing the compiled version of the lambda.</returns>
194 public new TDelegate Compile(DebugInfoGenerator debugInfoGenerator) {
195 ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
196 return (TDelegate)(object)LambdaCompiler.Compile(this, debugInfoGenerator);
200 /// Creates a new expression that is like this one, but using the
201 /// supplied children. If all of the children are the same, it will
202 /// return this expression.
204 /// <param name="body">The <see cref="LambdaExpression.Body">Body</see> property of the result.</param>
205 /// <param name="parameters">The <see cref="LambdaExpression.Parameters">Parameters</see> property of the result.</param>
206 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
207 public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters) {
208 if (body == Body && parameters == Parameters) {
211 return Expression.Lambda<TDelegate>(body, Name, TailCall, parameters);
215 /// Dispatches to the specific visit method for this node type.
217 protected internal override Expression Accept(ExpressionVisitor visitor) {
218 return visitor.VisitLambda(this);
221 internal override LambdaExpression Accept(StackSpiller spiller) {
222 return spiller.Rewrite(this);
225 internal static LambdaExpression Create(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
226 return new Expression<TDelegate>(body, name, tailCall, parameters);
231 public partial class Expression {
234 /// Creates an Expression{T} given the delegate type. Caches the
235 /// factory method to speed up repeated creations for the same T.
237 internal static LambdaExpression CreateLambda(Type delegateType, Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
238 // Get or create a delegate to the public Expression.Lambda<T>
239 // method and call that will be used for creating instances of this
241 LambdaFactory fastPath;
242 if (_LambdaFactories == null) {
243 // NOTE: this must be Interlocked assigment since we use _LambdaFactories for locking.
244 Interlocked.CompareExchange(ref _LambdaFactories, new CacheDict<Type, LambdaFactory>(50), null);
247 MethodInfo create = null;
248 lock (_LambdaFactories) {
249 if (!_LambdaFactories.TryGetValue(delegateType, out fastPath)) {
250 create = typeof(Expression<>).MakeGenericType(delegateType).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
251 if (TypeUtils.CanCache(delegateType)) {
252 _LambdaFactories[delegateType] = fastPath = (LambdaFactory)Delegate.CreateDelegate(typeof(LambdaFactory), create);
257 if (fastPath != null) {
258 return fastPath(body, name, tailCall, parameters);
261 Debug.Assert(create != null);
262 return (LambdaExpression)create.Invoke(null, new object[] { body, name, tailCall, parameters });
266 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
268 /// <typeparam name="TDelegate">The delegate type. </typeparam>
269 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
270 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
271 /// <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>
272 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) {
273 return Lambda<TDelegate>(body, false, (IEnumerable<ParameterExpression>)parameters);
277 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
279 /// <typeparam name="TDelegate">The delegate type. </typeparam>
280 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
281 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
282 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
283 /// <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>
284 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, params ParameterExpression[] parameters) {
285 return Lambda<TDelegate>(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
289 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
291 /// <typeparam name="TDelegate">The delegate type. </typeparam>
292 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
293 /// <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>
294 /// <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>
295 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, IEnumerable<ParameterExpression> parameters) {
296 return Lambda<TDelegate>(body, null, false, parameters);
300 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
302 /// <typeparam name="TDelegate">The delegate type. </typeparam>
303 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
304 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
305 /// <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>
306 /// <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>
307 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
308 return Lambda<TDelegate>(body, null, tailCall, parameters);
312 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
314 /// <typeparam name="TDelegate">The delegate type. </typeparam>
315 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
316 /// <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>
317 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
318 /// <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>
319 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, IEnumerable<ParameterExpression> parameters) {
320 return Lambda<TDelegate>(body, name, false, parameters);
324 /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time.
326 /// <typeparam name="TDelegate">The delegate type. </typeparam>
327 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
328 /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
329 /// <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>
330 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
331 /// <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>
332 public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
333 var parameterList = parameters.ToReadOnly();
334 ValidateLambdaArgs(typeof(TDelegate), ref body, parameterList);
335 return new Expression<TDelegate>(body, name, tailCall, parameterList);
340 /// Creates a LambdaExpression by first constructing a delegate type.
342 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
343 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
344 /// <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>
345 public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters) {
346 return Lambda(body, false, (IEnumerable<ParameterExpression>)parameters);
350 /// Creates a LambdaExpression by first constructing a delegate type.
352 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
353 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
354 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
355 /// <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>
356 public static LambdaExpression Lambda(Expression body, bool tailCall, params ParameterExpression[] parameters) {
357 return Lambda(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
361 /// Creates a LambdaExpression by first constructing a delegate type.
363 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
364 /// <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>
365 /// <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>
366 public static LambdaExpression Lambda(Expression body, IEnumerable<ParameterExpression> parameters) {
367 return Lambda(body, null, false, parameters);
371 /// Creates a LambdaExpression by first constructing a delegate type.
373 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
374 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
375 /// <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>
376 /// <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>
377 public static LambdaExpression Lambda(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
378 return Lambda(body, null, tailCall, parameters);
382 /// Creates a LambdaExpression by first constructing a delegate type.
384 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
385 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
386 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
387 /// <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>
388 public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) {
389 return Lambda(delegateType, body, null, false, parameters);
393 /// Creates a LambdaExpression by first constructing a delegate type.
395 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
396 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
397 /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
398 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
399 /// <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>
400 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, params ParameterExpression[] parameters) {
401 return Lambda(delegateType, body, null, tailCall, parameters);
405 /// Creates a LambdaExpression by first constructing a delegate type.
407 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
408 /// <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>
409 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
410 /// <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>
411 public static LambdaExpression Lambda(Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters) {
412 return Lambda(delegateType, body, null, false, parameters);
416 /// Creates a LambdaExpression by first constructing a delegate type.
418 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
419 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
420 /// <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>
421 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
422 /// <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>
423 public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
424 return Lambda(delegateType, body, null, tailCall, parameters);
428 /// Creates a LambdaExpression by first constructing a delegate type.
430 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
431 /// <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>
432 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
433 /// <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>
434 public static LambdaExpression Lambda(Expression body, string name, IEnumerable<ParameterExpression> parameters) {
435 return Lambda(body, name, false, parameters);
439 /// Creates a LambdaExpression by first constructing a delegate type.
441 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
442 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
443 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
444 /// <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>
445 /// <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>
446 public static LambdaExpression Lambda(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
447 ContractUtils.RequiresNotNull(body, "body");
449 var parameterList = parameters.ToReadOnly();
451 int paramCount = parameterList.Count;
452 Type[] typeArgs = new Type[paramCount + 1];
453 if (paramCount > 0) {
454 var set = new Set<ParameterExpression>(parameterList.Count);
455 for (int i = 0; i < paramCount; i++) {
456 var param = parameterList[i];
457 ContractUtils.RequiresNotNull(param, "parameter");
458 typeArgs[i] = param.IsByRef ? param.Type.MakeByRefType() : param.Type;
459 if (set.Contains(param)) {
460 throw Error.DuplicateVariable(param);
465 typeArgs[paramCount] = body.Type;
467 Type delegateType = DelegateHelpers.MakeDelegateType(typeArgs);
469 return CreateLambda(delegateType, body, name, tailCall, parameterList);
473 /// Creates a LambdaExpression by first constructing a delegate type.
475 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
476 /// <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>
477 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
478 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
479 /// <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>
480 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, IEnumerable<ParameterExpression> parameters) {
481 var paramList = parameters.ToReadOnly();
482 ValidateLambdaArgs(delegateType, ref body, paramList);
484 return CreateLambda(delegateType, body, name, false, paramList);
488 /// Creates a LambdaExpression by first constructing a delegate type.
490 /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
491 /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
492 /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
493 /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
494 /// <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>
495 /// <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>
496 public static LambdaExpression Lambda(Type delegateType, Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
497 var paramList = parameters.ToReadOnly();
498 ValidateLambdaArgs(delegateType, ref body, paramList);
500 return CreateLambda(delegateType, body, name, tailCall, paramList);
503 private static void ValidateLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection<ParameterExpression> parameters) {
504 ContractUtils.RequiresNotNull(delegateType, "delegateType");
505 RequiresCanRead(body, "body");
507 if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType) || delegateType == typeof(MulticastDelegate)) {
508 throw Error.LambdaTypeMustBeDerivedFromSystemDelegate();
512 lock (_LambdaDelegateCache) {
513 if (!_LambdaDelegateCache.TryGetValue(delegateType, out mi)) {
514 mi = delegateType.GetMethod("Invoke");
515 if (TypeUtils.CanCache(delegateType)) {
516 _LambdaDelegateCache[delegateType] = mi;
521 ParameterInfo[] pis = mi.GetParametersCached();
523 if (pis.Length > 0) {
524 if (pis.Length != parameters.Count) {
525 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
527 var set = new Set<ParameterExpression>(pis.Length);
528 for (int i = 0, n = pis.Length; i < n; i++) {
529 ParameterExpression pex = parameters[i];
530 ParameterInfo pi = pis[i];
531 RequiresCanRead(pex, "parameters");
532 Type pType = pi.ParameterType;
534 if (!pType.IsByRef) {
535 //We cannot pass a parameter of T& to a delegate that takes T or any non-ByRef type.
536 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type.MakeByRefType(), pType);
538 pType = pType.GetElementType();
540 if (!TypeUtils.AreReferenceAssignable(pex.Type, pType)) {
541 throw Error.ParameterExpressionNotValidAsDelegate(pex.Type, pType);
543 if (set.Contains(pex)) {
544 throw Error.DuplicateVariable(pex);
548 } else if (parameters.Count > 0) {
549 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
551 if (mi.ReturnType != typeof(void) && !TypeUtils.AreReferenceAssignable(mi.ReturnType, body.Type)) {
552 if (!TryQuote(mi.ReturnType, ref body)) {
553 throw Error.ExpressionTypeDoesNotMatchReturn(body.Type, mi.ReturnType);
558 private static bool ValidateTryGetFuncActionArgs(Type[] typeArgs) {
559 if (typeArgs == null) {
560 throw new ArgumentNullException("typeArgs");
562 for (int i = 0, n = typeArgs.Length; i < n; i++) {
565 throw new ArgumentNullException("typeArgs");
575 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
576 /// The last type argument specifies the return type of the created delegate.
578 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
579 /// <returns>The type of a System.Func delegate that has the specified type arguments.</returns>
580 public static Type GetFuncType(params Type[] typeArgs) {
581 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
583 Type result = DelegateHelpers.GetFuncType(typeArgs);
584 if (result == null) {
585 throw Error.IncorrectNumberOfTypeArgsForFunc();
591 /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
592 /// The last type argument specifies the return type of the created delegate.
594 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
595 /// <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>
596 /// <returns>true if generic System.Func delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
597 public static bool TryGetFuncType(Type[] typeArgs, out Type funcType) {
598 if (ValidateTryGetFuncActionArgs(typeArgs)) {
599 return (funcType = DelegateHelpers.GetFuncType(typeArgs)) != null;
606 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
608 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
609 /// <returns>The type of a System.Action delegate that has the specified type arguments.</returns>
610 public static Type GetActionType(params Type[] typeArgs) {
611 if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
613 Type result = DelegateHelpers.GetActionType(typeArgs);
614 if (result == null) {
615 throw Error.IncorrectNumberOfTypeArgsForAction();
621 /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
623 /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
624 /// <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>
625 /// <returns>true if generic System.Action delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
626 public static bool TryGetActionType(Type[] typeArgs, out Type actionType) {
627 if (ValidateTryGetFuncActionArgs(typeArgs)) {
628 return (actionType = DelegateHelpers.GetActionType(typeArgs)) != null;
635 /// Gets a <see cref="Type"/> object that represents a generic System.Func or System.Action delegate type that has specific type arguments.
636 /// The last type argument determines the return type of the delegate. If no Func or Action is large enough, it will generate a custom
639 /// <param name="typeArgs">The type arguments of the delegate.</param>
640 /// <returns>The delegate type.</returns>
642 /// As with Func, the last argument is the return type. It can be set
643 /// to System.Void to produce an Action.</remarks>
644 public static Type GetDelegateType(params Type[] typeArgs) {
645 ContractUtils.RequiresNotEmpty(typeArgs, "typeArgs");
646 ContractUtils.RequiresNotNullItems(typeArgs, "typeArgs");
647 return DelegateHelpers.MakeDelegateType(typeArgs);