C# 更改表达式的参数值<;Func<&书信电报;字符串>&燃气轮机;

C# 更改表达式的参数值<;Func<&书信电报;字符串>&燃气轮机;,c#,.net,expression,expression-trees,func,C#,.net,Expression,Expression Trees,Func,假设我有一个类项目,看起来像这样 public class Item { // .. Expression<Func<string>> Callback {get; set;} } public string TestFunction(string ident, DateTime value1, DateTime value2) { return string.Join(";", ident, value1, value2); } // ..

假设我有一个类项目,看起来像这样

public class Item
{
    // ..
    Expression<Func<string>> Callback {get; set;}
}
public string TestFunction(string ident, DateTime value1, DateTime value2)
{
    return string.Join(";", ident, value1, value2);
}

// ..

Item x = new Item();

x.Callback = () => TestFunction("Hello there", DateTime.Now.Date, DateTime.Now);

Console.WriteLine(x.Callback.Compile().Invoke()); // prints the expected output

这很管用。现在,我要做的是更改
DateTime
参数的值

我已经找到了获取参数的方法:

MethodCallExpression body = (MethodCallExpression)x.Callback.Body;

foreach(ConstantExpression arg in body.Arguments) {
    if(arg.Type == typeof(DateTime)) {
        //arg.Value =  => READONLY!
    }
}

但是,我无法为
arg.value
分配新值,因为它没有setter

似乎有一种叫做
ExpressionVisitor
的东西,但我不确定这是否是我需要的

有没有办法实现我的目标

先谢谢你

__

更新

我几乎可以在@Guru Stron help中使用它,但仍然有一个小问题

这段代码工作得非常好:

var newParams = new[] { Expression.Constant("testIdent"), Expression.Constant(DateTime.Now), Expression.Constant(DateTime.Now) };
但是,下面的代码抛出

Expression of type 'System.Linq.Expressions.ConstantExpression' cannot be used for parameter of type 'System.String' of method 'System.String TestFunction(System.String, System.DateTime, System.DateTime)'
例外

List<ConstantExpression> para = new List<ConstantExpression>();

foreach (var arg in body.Arguments) {
    if (arg.Type == typeof(DateTime)) {
        para.Add(Expression.Constant(DateTime.Now));
        continue;
    }

    para.Add(Expression.Constant(arg));
}

var exprBody = Expression.Call(body.Object, body.Method, para); // Exception is thrown here
List para=新列表();
foreach(body.Arguments中的变量arg){
if(arg.Type==typeof(DateTime)){
para.Add(Expression.Constant(DateTime.Now));
继续;
}
添加(表达式常数(arg));
}
var exprBody=Expression.Call(body.Object,body.Method,para);//这里抛出异常
错误很明显,但我似乎找不到将参数转换为正确类型的方法

我更改代码的原因是因为我不知道参数的数量,所以我尝试在它们之间循环任何只更改我需要的参数,因为顺序仍然正确


有什么想法吗?

您需要构建一个新的表达式,并向其传递新的所需参数:

MethodCallExpression body = (MethodCallExpression)x.Callback.Body;
var newParams = new[] { Expression.Constant("NEW "), Expression.Constant(DateTime.Now), Expression.Constant(DateTime.Now)};
var exprBody = Expression.Call(body.Object, body.Method, newParams );
var newExpr = Expression.Lambda<Func<string>>(exprBody);
var newFunc = newExpr.Compile();
Console.WriteLine(newFunc()); // "NEW ;03-Jun-20 5:07:16 PM;03-Jun-20 5:07:16 PM"
MethodCallExpression body=(MethodCallExpression)x.Callback.body;
var newParams=new[]{Expression.Constant(“new”)、Expression.Constant(DateTime.Now)、Expression.Constant(DateTime.Now)};
var exprBody=Expression.Call(body.Object、body.Method、newParams);
var newExpr=Expression.Lambda(exprBody);
var newFunc=newExpr.Compile();
Console.WriteLine(newFunc());//“新建;20年6月3日下午5:07:16;20年6月3日下午5:07:16”

@Shawn很乐意帮忙!只是出于兴趣:像
.Compile
这样的调用是否被缓存?我记得反射环境中的某些调用将被缓存,所以这里可能也是这样。@Shawn AFAIK不,您需要自己缓存它们。好的,谢谢。实际上我遇到了一个新问题,我已经更新了帖子。你也能看一下吗?@Shawn将
para
更改为
var para=new List()
段落添加(表达式常数(arg))
段落添加(arg)