首页 > 解决方案 > 更改表达式的参数值>

问题描述

假设我有一个看起来像这样的类 Item

public class Item
{
    // ..
    Expression<Func<string>> Callback {get; set;}
}

Item定义了一个Callback可以像这样使用的属性

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因为没有设置器。

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

有什么办法可以实现我想要做的事情吗?

先感谢您

__

更新

我几乎可以在@Guru Stron 的帮助下完成它,但仍然存在一个小问题。

这段代码工作得很好:

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

错误很明显,但我似乎找不到将参数转换为正确类型的方法。

我更改代码的原因是因为我不知道参数的数量,所以我尝试循环遍历它们,只更改我需要的参数,因为顺序保持正确。

有任何想法吗?

标签: c#.netexpressionexpression-treesfunc

解决方案


您将需要构建一个新表达式并将新的所需参数传递给它:

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"

推荐阅读