替换lambda表达式中的参数

Dyn*_*ard 6 c# lambda delegates expression

我有一部分代码在运行时接受lambda表达式,然后我可以编译和调用它.

Something thing;

Expression<Action<Something>> expression = (c => c.DoWork());
Delegate del = expression.Compile();
del.DynamicInvoke(thing);
Run Code Online (Sandbox Code Playgroud)

为了节省执行时间,我将这些已编译的委托存储在缓存中,Dictionary<String, Delegate>其中键是lambda表达式字符串.

cache.Add("(Something)c => c.DoWork()", del);
Run Code Online (Sandbox Code Playgroud)

对于完全相同的调用,它工作正常.但是我意识到我可以收到相当的lambda,例如"d => d.DoWork()",我实际上应该使用相同的委托,而我不是.

这让我想知道是否有一种干净的方式(读取"不使用String.Replace",我已经将其作为临时修复)来替换lambda表达式中的元素,比如可能替换它们arg0以便两者都可以

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

(arg0 => arg0.DoWork())通过使用类似于在lambda中注入Expression.Parameter(Type,Name)的东西进行转换和比较.

那可能吗 ?(答案可以包括C#4.0)

Ale*_*ina 3

我使用了字符串,因为这对我来说是最简单的方法。您无法手动更改参数表达式的名称(它具有“Name”属性,但它是只读的),因此您必须从片段构造一个新表达式。我所做的是创建一个“无名”参数(实际上,在本例中它获得一个自动生成的名称,即“Param_0”),然后创建一个与旧表达式几乎相同的新表达式,但使用新参数。

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();
}
Run Code Online (Sandbox Code Playgroud)