Replacing parameters in a lambda expression

I had a piece of code that takes lambda expressions at runtime that I can compile and invoke.

Something thing; Expression<Action<Something>> expression = (c => c.DoWork()); Delegate del = expression.Compile(); del.DynamicInvoke(thing); 

To save runtime, I saved these compiled delegates to cache, Dictionary<String, Delegate> , which is the string of the lambda expression.

 cache.Add("(Something)c => c.DoWork()", del); 

For the same calls, it worked fine. However, I realized that I could get equivalent lambdas, such as "d => d.DoWork ()", on which I should use the same delegate, but I was not.

This made me wonder if there was a clean path (read “not using String.Replace”, I already did it as a temporary fix) to replace the elements in the lambda expression, for example, possibly replacing them with arg0 so that both

(c => c.DoWork()) and (d => d.DoWork())

are converted and compared as (arg0 => arg0.DoWork()) , using something fuctionnally similar to an injection of an expression. Parameter (Type, Name) in lambda.

Is it possible? (Answers may include C # 4.0)

+6
c # lambda expression delegates
source share
2 answers

I used strings since this was the easiest way for me. You cannot manually change the name of the parameter expression (it has the "Name" property, but it is read-only), so you must build a new expression from fragments. What I did was created by the "nameless" parameter (in fact, in this case it gets the auto-generated name, which is "Param_0"), and then created a new expression, almost the same as the old one, but using the new parameter.

 public static void Main() { String thing = "test"; Expression<Action<String>> expression = c => c.ToUpper(); Delegate del = expression.Compile(); del.DynamicInvoke(thing); Dictionary<String, Delegate> cache = new Dictionary<String, Delegate>(); cache.Add(GenerateKey(expression), del); Expression<Action<String>> expression1 = d => d.ToUpper(); var test = cache.ContainsKey(GenerateKey(expression1)); Console.WriteLine(test); } public static string GenerateKey(Expression<Action<String>> expr) { ParameterExpression newParam = Expression.Parameter(expr.Parameters[0].Type); Expression newExprBody = Expression.Call(newParam, ((MethodCallExpression)expr.Body).Method); Expression<Action<String>> newExpr = Expression.Lambda<Action<String>>(newExprBody, newParam); return newExpr.ToString(); } 
+3
source share

There is more lambda expression than just text. Lambdas are being rewritten by the compiler into something much more complex. For example, they may close variables (which may include other delegates). This means that two lambdas can look exactly the same, but perform completely different actions.

Thus, you may need to cache your compiled expression, but you need to give them a more meaningful name for the key than just the text of the expression. Otherwise, replacing the arguments will not help you.

+3
source share

All Articles