public void Add(NestedLambdaInfo nestedLambdaInfo) { if (NestedLambdas == null) { NestedLambdas = new List <NestedLambdaInfo>(); } NestedLambdas.Add(nestedLambdaInfo); }
// @paramExprs is required for nested lambda compilation private static bool TryCollectBoundConstants(ref ClosureInfo closure, Expression expr, IList <ParameterExpression> paramExprs) { if (expr == null) { return(false); } switch (expr.NodeType) { case ExpressionType.Constant: var constantExpr = (ConstantExpression)expr; var constantValue = constantExpr.Value; if (constantValue is Delegate || IsBoundConstant(constantValue)) { closure = closure ?? new ClosureInfo(); closure.Add(constantExpr); } break; case ExpressionType.Parameter: // if parameter is used but no passed we assume that it should be in closure and set by outer lambda var paramExpr = (ParameterExpression)expr; if (paramExprs.IndexOf(paramExpr) == -1) { closure = closure ?? new ClosureInfo(); closure.Add(paramExpr); } break; case ExpressionType.Call: var methodCallExpr = (MethodCallExpression)expr; var methodOwnerExpr = methodCallExpr.Object; return((methodOwnerExpr == null || TryCollectBoundConstants(ref closure, methodOwnerExpr, paramExprs)) && TryCollectBoundConstants(ref closure, methodCallExpr.Arguments, paramExprs)); case ExpressionType.MemberAccess: return(TryCollectBoundConstants(ref closure, ((MemberExpression)expr).Expression, paramExprs)); case ExpressionType.New: return(TryCollectBoundConstants(ref closure, ((NewExpression)expr).Arguments, paramExprs)); case ExpressionType.NewArrayInit: return(TryCollectBoundConstants(ref closure, ((NewArrayExpression)expr).Expressions, paramExprs)); // property initializer case ExpressionType.MemberInit: var memberInitExpr = (MemberInitExpression)expr; if (!TryCollectBoundConstants(ref closure, memberInitExpr.NewExpression, paramExprs)) { return(false); } var memberBindings = memberInitExpr.Bindings; for (var i = 0; i < memberBindings.Count; ++i) { var memberBinding = memberBindings[i]; if (memberBinding.BindingType == MemberBindingType.Assignment && !TryCollectBoundConstants(ref closure, ((MemberAssignment)memberBinding).Expression, paramExprs)) { return(false); } } break; // nested lambda case ExpressionType.Lambda: var lambdaExpr = (LambdaExpression)expr; var lambdaParamExprs = lambdaExpr.Parameters; var paramTypes = GetParamExprTypes(lambdaParamExprs); ClosureInfo nestedClosure = null; var nestedLambda = TryCompile(ref nestedClosure, lambdaExpr.Type, paramTypes, lambdaExpr.Body.Type, lambdaExpr.Body, lambdaParamExprs); if (nestedLambda == null) { return(false); } var nestedLambdaInfo = new NestedLambdaInfo(nestedLambda, expr, nestedClosure); closure = closure ?? new ClosureInfo(); closure.Add(nestedLambdaInfo); // if nested parameter is no matched with any outer parameter, that ensure it goes to outer closure if (nestedClosure != null && nestedClosure.UsedParamExpressions != null) { var nestedClosedParams = nestedClosure.UsedParamExpressions; for (var i = 0; i < nestedClosedParams.Count; i++) { var nestedClosedParamExpr = nestedClosedParams[i]; if (paramExprs.Count == 0 || paramExprs.IndexOf(nestedClosedParamExpr) == -1) { closure.Add(nestedClosedParamExpr); } } } break; case ExpressionType.Invoke: var invocationExpr = (InvocationExpression)expr; return(TryCollectBoundConstants(ref closure, invocationExpr.Expression, paramExprs) && TryCollectBoundConstants(ref closure, invocationExpr.Arguments, paramExprs)); default: var unaryExpr = expr as UnaryExpression; if (unaryExpr != null) { return(TryCollectBoundConstants(ref closure, unaryExpr.Operand, paramExprs)); } var binaryExpr = expr as BinaryExpression; if (binaryExpr != null) { return(TryCollectBoundConstants(ref closure, binaryExpr.Left, paramExprs) && TryCollectBoundConstants(ref closure, binaryExpr.Right, paramExprs)); } break; } return(true); }