tags:

views:

22

answers:

2

Hello,

I'm using MethodCallExpression to record method calls.

public void RegisterInvocation<TSource>(TSource target, Expression<Action<TSource>> selector)
{
   ...
}

Somewhen later I execute the expression like this:

selector.Compile().Invoke();

And here I have a strange effekt (perhaps I missunderstand 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?

Thanks for help, Enyra

+1  A: 

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();
}
Timwi
at the moment this is my workaround, but I would prefer a solution where I can fix this behavior internally.
Enyra
@Enyra: This is not a workaround, this is the correct solution. You can’t change the behaviour of lambda expressions because this is how they are defined.
Timwi
yes i'm aware of ^^ thanks for your help
Enyra
A: 

This is because you mutated the captured variable (item).

leppie