如何将MethodCallExpression与方法参数一起使用

时间:2010-08-30 09:17:30

标签: c# lambda

我正在使用MethodCallExpression来记录方法调用。

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

稍后我会执行这样的表达式:

selector.Compile().Invoke();

在这里我有一个奇怪的效果(也许我误解了方法调用表达式)。

如果我使用普通变量或常量参数注册方法调用,则使用正确的参数调用方法:

string item = "sometext";
instance.RegisterInvocation<ITarget>(this, p => p.Add(item));

但是如果我使用实例变量参数注册方法调用,则在执行时而不是在注册时使用实例变量的参数值调用该方法:

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"
   }
}

有没有办法在注册时使用参数调用方法调用表达式?

2 个答案:

答案 0 :(得分:2)

您看到此行为的原因是因为lambda表达式

p => p.Add(this.item)

“捕获”字段item(而不是其值)。当表达式树被编译成lambda时,它仍将包含对该字段的引用,而不是它当时的值。如果您想确保在注册时拥有该值,您可以复制该值:

public void DoSomething()
{
    this.item = "sometext";
    var itemCopy = item;
    instance.RegisterInvocation<ITarget>(this, p => p.Add(itemCopy));

    this.item = "anothertext";
    instance.CallRegisteredInvocation();
}

答案 1 :(得分:0)

这是因为您改变了捕获的变量(item)。