public VariadicArrayParametersDelegate CachedCompileLambda(LambdaExpression lambda) { IReadOnlyList <object> constants; ParameterListDelegate compiled; if (delegates.TryGetValue(lambda, out compiled)) { constants = ConstantExtractor.ExtractConstantsOnly(lambda.Body); } else { var extractionResult = ConstantExtractor.ExtractConstants(lambda.Body); compiled = ParameterListRewriter.RewriteLambda( Expression.Lambda( extractionResult.ConstantfreeExpression.Body, extractionResult.ConstantfreeExpression.Parameters.Concat(lambda.Parameters))) .Compile(); var key = getClosureFreeKeyForCaching(extractionResult, lambda.Parameters); delegates.TryAdd(key, compiled); constants = extractionResult.ExtractedConstants; } return(args => compiled(constants.Concat(args).ToArray())); }
public static LambdaExpression Extract(Expression exp, out IList <object> values) { var extractor = new ConstantExtractor(); var body = extractor.Visit(exp); values = extractor.constantValues.ToArray(); if (values.Count >= 5) { // Can't create a lambda with more than 4 parameters. Go figure. values = new object[] { values }; return(ParamArrayRewriter.Rewrite(body, extractor.newParameters.ToArray())); } return(Expression.Lambda(body, extractor.newParameters.ToArray())); }
public void SimpleTest() { var ex = new ConstantExtractor(CreateAdd(1)); var ey = new ConstantExtractor(CreateAdd(2)); var tx = ex.Process().ToExpressionTree(); var ty = ey.Process().ToExpressionTree(); var cx = (int)ex.GetConstants()[0]; var cy = (int)ey.GetConstants()[0]; Assert.AreEqual(cx, 1); Assert.AreEqual(cy, 2); Assert.AreEqual(tx, ty); }
/// <inheritdoc/> public override object Execute(Expression expression) { if (expression.NodeType != ExpressionType.Call) { throw new Exception("Unsupported node type: " + expression.NodeType); } var m = (MethodCallExpression)expression; if (m.Method.Name != "Select") { throw new Exception("Unsupported method: " + m.Method.Name); } // Pull out the constants from the new expression IList <object> values; var extractedLambda = ConstantExtractor.Extract(m, out values); // Now get compiled version from cache, or create as appropriate var cacheKey = new CacheEntry(m); var cachedEntry = GetCachedEntry(cacheKey); if (cachedEntry == null) { Type dataType = m.Method.GetGenericArguments()[0]; // Queryable.Select<TSource,TResult>(...) // Perform the translation to using FudgeMsgs rather than the data type var translator = new FudgeExpressionTranslator(dataType, source); var newSelect = (LambdaExpression)translator.Translate(extractedLambda); // We can now create a fully-fledged cache entry cachedEntry = new CacheEntry(cacheKey, newSelect.Compile()); AddCacheEntry(cachedEntry); } return(cachedEntry.Invoke(values.ToArray())); }