/// <summary> /// Creates an <see cref="Expression{TDelegate}" /> where the delegate type is known at compile time. /// </summary> /// <param name="isAsync">Indicates whether the resulting lambda is synchronous or asynchronous.</param> /// <param name="body">An <see cref="Expression" /> representing the body of the lambda.</param> /// <param name="parameters">An array of <see cref="ParameterExpression" /> objects that represent the parameters passed to the lambda.</param> /// <returns>An expression representing a lambda with the specified body and parameters.</returns> public static Expression <TDelegate> Lambda <TDelegate>(bool isAsync, Expression body, params ParameterExpression[] parameters) { // NB: If we were to omit the isAsync parameter, we could try to check the TDelegate return type and // match it with the body type to determine whether the intent is to create a sync or an async // lambda. However, for a return type of void, it's unclear what the intent is. We could resort // to scanning the body looking for await expressions. None of these techniques aligns well with // the explicitness in the language wrt the async modifier, so we shy away from any such smarts. // // NB: Ultimately, this overload should likely go away and the language should bind to AsyncLambda in // case of emitting an expression tree for an async lambda. Right now, the overload exists to have // assignment compatibility with Expression<T> for async lambdas, so we don't have to extend the // language with AsyncCSharpExpression<T> as a type to consider for lambda convertibility. Notice // though that the async case here causes an expression tree to be created that's not very natural // to say the least. It does, however, compile and evaluate just fine at runtime. In order to lift // this restriction, we have to either extend LINQ to support async Expression<T> or unseal it to // allow for our library to create derived async variants. if (isAsync) { var async = CSharpExpression.AsyncLambda <TDelegate>(body, parameters); return(Expression.Lambda <TDelegate>(Expression.Invoke(async, parameters), parameters)); } else { return(Expression.Lambda <TDelegate>(body, parameters)); } }
/// <summary> /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will return this expression. /// </summary> /// <param name="body">The <see cref="AsyncLambdaCSharpExpression.Body" /> property of the result.</param> /// <param name="parameters">The <see cref="AsyncLambdaCSharpExpression.Parameters" /> property of the result. </param> /// <returns>This expression if no children changed, or an expression with the updated children.</returns> public AsyncCSharpExpression <TDelegate> Update(Expression body, IEnumerable <ParameterExpression> parameters) { if (body == Body && SameElements(ref parameters, Parameters)) { return(this); } return(CSharpExpression.AsyncLambda <TDelegate>(body, parameters)); }
/// <summary> /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will return this expression. /// </summary> /// <param name="body">The <see cref="AsyncLambdaCSharpExpression.Body" /> property of the result.</param> /// <param name="parameters">The <see cref="AsyncLambdaCSharpExpression.Parameters" /> property of the result. </param> /// <returns>This expression if no children changed, or an expression with the updated children.</returns> public AsyncCSharpExpression <TDelegate> Update(Expression body, IEnumerable <ParameterExpression> parameters) { if (body == base.Body && parameters == base.Parameters) { return(this); } return(CSharpExpression.AsyncLambda <TDelegate>(body, parameters)); }