How to use MethodCallExpression with method arguments
I'm using MethodCallExpression to record method calls.
public void RegisterInvocation<TSource>
(TSource target, Expressio开发者_Go百科n<Action<TSource>> selector)
{
...
}
Somewhen later I execute the expression like this:
selector.Compile().Invoke();
And here I have a strange effect (perhaps I misunderstand something with Method Call Expressions).
If I register a method call with normal variable or constant arguments, the methods gets called with the correct arguments:
string item = "sometext";
instance.RegisterInvocation<ITarget>(this, p => p.Add(item));
But if I register a method call with an instance variable arguments, the method gets called with argument values of the instance variable at execution time and not at registration time:
public class Target : ITarget
{
string item;
public void DoSomething()
{
this.item = "sometext";
instance.RegisterInvocation<ITarget>(this, p => p.Add(this.item));
this.item = "anothertext";
instance.CallRegisteredInvocation();
}
public void Add(string item)
{
// "somestring" expected, but item is = "anotherstring"
}
}
Is there a way to invoke the method call expression with arguments at registration time?
The reason you are seeing this behaviour is because the lambda expression
p => p.Add(this.item)
“captures” the field item
(rather than its value). When the expression tree is compiled into a lambda, it will still contain a reference to that field rather than the value it had at the time. If you want to make sure that you have the value at the time of registration, you can make a copy of that value:
public void DoSomething()
{
this.item = "sometext";
var itemCopy = item;
instance.RegisterInvocation<ITarget>(this, p => p.Add(itemCopy));
this.item = "anothertext";
instance.CallRegisteredInvocation();
}
This is because you mutated the captured variable (item
).
精彩评论