C#代表,参考解析时间

Eki*_*Koc 7 .net c# multithreading delegates naming-conventions

我有一个关于.net委托的简单问题.说我有这样的事情:

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

    public void Invoke(Action action)
    {
        m_TaskQueue.Enqueue(action);
    }
Run Code Online (Sandbox Code Playgroud)

第一个函数包含对引用的引用this.Value.在运行时,当第一个带有泛型参数的方法被调用时,它会this.Value以某种方式提供给第二个,但是如何?我想到了这些:

  • 按值调用(struct) - this.Value传递的当前值,因此如果在m_TaskQueue5分钟后执行它,则该值将不会处于其最近状态,它将是第一次引用时的值.
  • 通过引用调用(引用类型) - 然后Value在执行操作期间将引用最新状态,但如果this.Value在执行操作之前我更改为另一个引用,它仍将指向旧引用
  • 按名称调用(两者) - this.Value调用操作时将在何处进行评估.我相信实际的实现将持有一个引用,this然后Value在实际执行委托期间对其进行评估,因为没有按名称调用.

我认为这将是名称样式的调用,但无法找到任何文档,所以想知道它是否是一个明确定义的行为.这个类类似于Scala或Erlang中的Actor,所以我需要它是线程安全的.我不希望Invoke函数Value立即取消引用,这将在this对象的安全线程中完成m_TaskQueue.

Eri*_*ert 19

让我通过描述我们为此实际生成的代码来回答您的问题.我将重命名你容易混淆的其他Invoke方法; 没有必要了解这里发生了什么.

假设你说

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

编译器生成代码,就像您实际编写的一样:

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
  } 
}
Run Code Online (Sandbox Code Playgroud)

这是否回答你的问题?


Mar*_*ers 8

委托存储对变量的引用,而不是它的值.如果你想保持当前值(假设它是一个值类型),你需要制作它的本地副本:

public void Invoke(Action<T> action)
{
    var localValue = this.Value;
    Invoke(() => action(localValue));
}
Run Code Online (Sandbox Code Playgroud)

如果它是可变引用类型,则可以创建本地克隆/深层副本.