Control.Invoke()和Control.BeginInvoke() - 过去的参数存储在哪里?如何处理它?

3
我已经阅读了很多关于Control.Invoke和Control.BeginInvoke的文章,了解到Invoke类似于SendMessage(),而BeginInvoke则类似于PostMessage()。然而我不明白通过new object[] { arg, arg, arg, ...}传递的参数列表存储在哪里。在传统调用中,参数被推送到堆栈中并在被调用函数内部弹出,然后从堆栈中恢复调用帧,我假设释放任何对堆对象的引用,允许它们被收集。那么,Invoke/BeginInvoke的推送栈数据存储在哪里?方法调用退出后如何处理它?
此外,我已经成功地调用控件方法,而没有使用新的对象数组来传递参数。为什么这样可以工作?更好的是,既然这能够工作,为什么我看到的所有例子都使用一个新的对象数组呢?
这是我一直看到和使用的内容:
BeginInvoke(FormReceiveEvent, new object[] { Event, Arg1, Arg2, Arg3 });

但这也可以:
BeginInvoke(FormReceiveEvent, Event, Arg1, Arg2, Arg3);

任何信息和评论都非常受欢迎... 预先感谢您。
3个回答

1

object[] 包含参数的对象在异步调用目标委托时由 BeginInvoke 方法内部存储。一旦异步调用完成,对数组的引用将被释放,允许收集数组及其内容(假设它们没有被其他方式引用)。

BeginInvoke(FormReceiveEvent, Event, Arg1, Arg2, Arg3); 形式之所以有效,是因为 BeginInvoke 的第二个参数被定义为 params object[]。这意味着如果您没有显式创建一个数组,编译器会为您创建一个数组。因此,从运行时行为上看,这两个调用是相同的。


关于术语的说明:在 .Net 的上下文中,说一个对象被“disposed”通常意味着该对象实现了 IDisposable 接口,并且其 IDisposable.Dispose 方法已被调用。但在 Control.BeginInvokeControl.Invoke 的上下文中,情况并非如此。
异步调用完成后,对 object[] 的引用将被释放,以便进行回收,但如果其中任何成员实现了 IDisposable 接口,则不会调用 IDisposable.Dispose 方法。直到该对象被回收(或其他人处理它),其资源才会被释放。

很好的观点。对于误用dispose我感到抱歉。只要没有对该对象的引用,且GC发生了,它就会调用IDisposble的dispose方法吗?再次感谢。 - CCS
@CCS:如果实现了 IDisposable 接口的对象包含任何非托管资源,则这些资源也应该由对象的终结器释放,以便在对象在被收集之前未被处理时仍然会被释放。通常的模式是拥有一个 Dispose(bool) 方法,而 IDisposable.Dispose 方法调用 Dispose(true),终结器调用 Dispose(false) - Sven

0

并不总是传递的参数会被存储在栈中。只有值类型才会被存储在栈中,否则引用会被存储在栈中,并查找指向堆中的引用类型。

在这种情况下,同样也适用。对象数组和将其作为单独的数组传递的区别,我想是在栈上的分配。如果您单独传递它们,则会分配更多的堆栈空间。而对于指向堆中N个数组对象的引用,则在栈中分配了一个引用。

欢迎纠正我。


值类型不需要在堆栈上传递。Jitter 可能会选择将它们注册。 - Eric Lippert
不用担心,Eric。我已经看到你的回答了。https://dev59.com/unE85IYBdhLWcg3wQxLG#2866346 阅读完这篇文章后,我可以说值类型的存储大多在堆栈上,但也有可能在其他地方,这可能是.NET实现的秘密吗? - Zenwalker

0

当将某个对象传递给Control.InvokeControl.BeginInvoke时,您正在将参数传递给一个"方法",这与传递参数给任何方法没有区别。但是,如果您对InvokeBeginInvoke的实现感到好奇,可以在此answer中查看。

对于问题的第二部分,BeginInvoke的签名如下:

BeginInvoke(Delegate method, params object[] args);

所以你在询问params关键字,这是一个特殊的关键字,允许你将n个参数或特定类型的数组传递给方法。

params关键字允许你指定一个接受可变数量参数的方法参数。 你可以发送一个由逗号分隔的参数列表,这些参数的类型在参数声明中指定,或者一个指定类型的参数数组。你也可以不发送任何参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接