C# 如何生成对方法参数的“表达式”引用

C# 如何生成对方法参数的“表达式”引用,c#,reflection,expression-trees,C#,Reflection,Expression Trees,如果我有一个使用Expression树构建代码的方法来处理运行时类型,那么如何生成引用该方法参数的Expression 例如,在下面的代码中,如何构建表达式s以传入该引用方法参数 public static bool ExpressionContains(string s, string sub) { var cmi = typeof(String).GetMethod("Contains", new[] { typeof(string) }); var body = Expre

如果我有一个使用
Expression
树构建代码的方法来处理运行时类型,那么如何生成引用该方法参数的
Expression

例如,在下面的代码中,如何构建
表达式
s以传入该引用方法参数

public static bool ExpressionContains(string s, string sub) {
    var cmi = typeof(String).GetMethod("Contains", new[] { typeof(string) });
    var body = Expression.Call(cmi, s ???, sub ???);

    return Expression.Lambda<Func<bool>>(body).Compile().Invoke();
}
public static bool ExpressionContains(字符串s,字符串sub){
var cmi=typeof(String).GetMethod(“Contains”,new[]{typeof(String)});
var body=表达式调用(cmi,s???,sub??);
返回表达式.Lambda(body.Compile().Invoke();
}

由于表达式编译为
Func
,就其而言,
s
sub
的值是常量:

public static bool ExpressionContains(string s, string sub) {
    var cmi = typeof(String).GetMethod("Contains", new[] { typeof(string) });
    var body = Expression.Call(
        Expression.Constant(s),
        cmi,
        Expression.Constant(sub));

    return Expression.Lambda<Func<bool>>(body).Compile().Invoke();
}

有趣的是(对我来说),从lambda构建的
表达式
使用
成员访问
字段表达式
而不是
常量表达式
。lambda将捕获s,而委托捕获局部变量的方式是将局部变量提升到新类中的字段中,委托方法是在这个类上定义的,所以我打赌类似的事情也发生在你身上。该字段所在的类肯定是一个常量。这确实需要重写lambda周围的代码,如果手动编写表达式,则无法获得该功能,因此它不适用于您的问题。但是我不认为列表有什么问题?引用本身是一个常量,但基础列表仍然是同一个可变对象。恐怕我现在在移动设备上,要到明天晚上才能添加到我的答案中,但请更改我的第一个代码段,使其包含字符串列表和字符串,并在传递字符串的列表上调用list的add方法。它将改变调用方传入的列表。在我的场景中,这应该可以正常工作,但我可以看到在某些场景中不提升可能会导致问题,但听起来需要修复的工作量很大。只有在编写lambda时,您才能让编译器为您执行提升。如果您手工编写表达式,则必须手工完成提升:让调用方构造一个可变容器,其中包含您希望能够重新分配的任何变量。
public static bool ExpressionContains(string s, string sub) {
    var sExpr = Expression.Parameter(typeof(string), "s");
    var subExpr = Expression.Parameter(typeof(string), "sub");
    var cmi = typeof(String).GetMethod("Contains", new[] { typeof(string) });
    var body = Expression.Call(sExpr, cmi, subExpr);

    return Expression.Lambda<Func<string, string, bool>>(body, new[] { sExpr, subExpr }).Compile().Invoke(s, sub);
}