C# delegates, reference resolution time

混江龙づ霸主 提交于 2019-12-05 05:38:06

Let me answer your question by describing what code we actually generate for this. I'll rename your confusingly-named other Invoke method; it's not necessary to understanding what's going on here.

Suppose you said

class C<T>
{
  public T Value;
  public void Invoke(Action<T> action) 
  { 
      Frob(() => action(this.Value)); 
  } 
  public void Frob(Action action) 
  {  // whatever
  } 
}

The compiler generates code as though you had actually written:

class C<T>
{
  public T Value;

  private class CLOSURE
  {
     public Action<T> ACTION;
     public C<T> THIS;
     public void METHOD()
     {
       this.ACTION(this.THIS.Value);
     }
  }

  public void Invoke(Action<T> action) 
  { 
      CLOSURE closure = new CLOSURE();
      closure.THIS = this;
      closure.ACTION = action;
      Frob(new Action(closure.METHOD)); 
  } 
  public void Frob(Action action) 
  {  // whatever
  } 
}

Does that answer your question?

The delegate stores a reference to the variable, not the value of it. If you want to keep the current value then (assuming it is a value type) you need to make a local copy of it:

public void Invoke(Action<T> action)
{
    var localValue = this.Value;
    Invoke(() => action(localValue));
}

If it is a mutable reference type you could make a local clone / deep copy.

The real key is to remember that scope is lexical; it's something the compiler takes care of. So it captures variables, not their values. Whether those values are value types or reference types is another matter completely.

Maybe a slightly more extreme example of altering the behavior of the delegate will help:

var myVariable = "something";
Action a = () => Console.WriteLine(myVariable);
myVariable = "something else entirely"
a();

prints "something else entirely". In that light, it doesn't really matter how many times you wrap, save, or move the function; it still refers to the variable it enclosed. So, in short, what matters is the value of the enclosed variable when the delegate's actually executed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!