C#代表,参考解析时间
我有一个关于 .net 代表的简单问题。假设我有这样的东西:
public void Invoke(Action<T> action)
{
Invoke(() => action(this.Value));
}
public void Invoke(Action action)
{
m_TaskQueue.Enqueue(action);
}
第一个函数包含对 this.Value
的引用。在运行时,当第一个带有泛型参数的方法被调用时,它将以某种方式向第二个方法提供 this.Value ,但是如何提供呢?我想到了这些:
- 按值调用(结构) -
this.Value
的当前值被传递,因此如果m_TaskQueue
执行它5 分钟后,该值将不再是最近的状态,它将是第一次引用时的值。 - 通过引用调用(引用类型) - 那么在执行操作期间将引用
Value
的最新状态,但如果我更改this.Value
在执行操作之前指向另一个引用,它仍将指向旧引用 - 按名称调用(两者) - 其中
this.Value
将在调用操作时进行评估。我相信实际的实现将持有对this
的引用,然后在委托的实际执行期间评估Value
,因为没有按名称调用。
我认为这将是名称风格的调用,但找不到任何文档,所以想知道这是否是一个明确定义的行为。这个类类似于 Scala 或 Erlang 中的 Actor,所以我需要它是线程安全的。我不希望 Invoke
函数立即取消引用 Value
,这将由 m_TaskQueue
在 this
对象的安全线程中完成代码>.
I have a simple question about .net delegates. Say I have something like this:
public void Invoke(Action<T> action)
{
Invoke(() => action(this.Value));
}
public void Invoke(Action action)
{
m_TaskQueue.Enqueue(action);
}
The first function encloses a reference to this.Value
. During runtime, when the first, method with generic parameter gets called, it will provide this.Value
somehow to the second one, but how? These came into my mind:
- Call by value (struct) - the current value of
this.Value
gets passed, so if them_TaskQueue
executes it 5 minutes later, the value will not be in its recent state, it will be whatever it was when first referencing. - Call by reference (reference type) - then the most recent state of
Value
will be referenced during execution of action but if I changethis.Value
to another reference before execution of action, it will still be pointing to the old reference - Call by name (both) - where
this.Value
will be evaluated when the action gets called. I believe the actual implementation would be holding a reference tothis
then evaluateValue
on that during actual execution of delegate since there is no call by name.
I assume it would be Call of name style but could not find any documentation so wondering if it is a well-defined behavior. This class is something like an Actor in Scala or Erlang so I need it to be thread safe. I do not want Invoke
function to dereference Value
immediately, that will be done in a safe thread for this
object by m_TaskQueue
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
让我通过描述我们实际为此生成的代码来回答您的问题。我将重命名您名称混乱的其他 Invoke 方法;没有必要了解这里发生了什么。
假设您说
编译器生成代码就像您实际编写的一样:
这回答了您的问题吗?
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
The compiler generates code as though you had actually written:
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:
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:
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.