Let's say I've got the class Item which looks like this
public class Item
{
// ..
Expression<Func<string>> Callback {get; set;}
}
Item
defines a property called Callback
which can be used like this
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
That works just well. Now, what I'm trying to do is change the value of the DateTime
parameters.
I've already figured out how to get the arguments:
MethodCallExpression body = (MethodCallExpression)x.Callback.Body;
foreach(ConstantExpression arg in body.Arguments) {
if(arg.Type == typeof(DateTime)) {
//arg.Value = => READONLY!
}
}
However, I can't assign a new value to arg.Value
because doesn't have a setter.
There seems to be something called ExpressionVisitor
but I'm unsure if that's something I need.
Is there any way to achieve what I'm trying to do?
Thank you in advance
__
Update
I almost got it working with @Guru Stron help but there's still a small problem.
This piece of code works perfectly fine:
var newParams = new[] { Expression.Constant("testIdent"), Expression.Constant(DateTime.Now), Expression.Constant(DateTime.Now) };
However, the following code throws an
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)'
Exception.
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
The error is pretty obvious but I can't seem to find a way to convert the parameter to the correct type.
The reason why I changed the code is because I don't know the amount of parameters, so I tried to loop through them any only change the ones I need since the order remains correct.
Any ideas?
You will need to build a new expression and pass new desired parameters to it:
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"