简体   繁体   English

事件参数是通过C#中的引用还是通过值传递的?

[英]Are event arguments passed by reference or value in C#?

A rather simple question (I think), but I don't seem to see an answer already. 一个相当简单的问题(我认为),但是我似乎还没有看到答案。 I know that some values are passed via value (like int and long), and others are passed by reference (like Strings) when you pass them to functions. 我知道有些值是通过值传递的(如int和long),而有些值是通过引用传递的(如Strings),当您将它们传递给函数时。

In my program, I have it using background worker so that the GUI doesn't lock up when we are doing a long process in the background. 在我的程序中,我使用后台工作程序来执行此操作,因此当我们在后台进行长时间处理时,GUI不会锁定。 I need to pass data back to the UI thread from another file, so I have been using events for that. 我需要将数据从另一个文件传递回UI线程,因此我一直在使用事件。 Now I need to send a list of arrays of Strings back to the GUI thread to handle there, and I am worried how it will be handled. 现在,我需要将字符串数组的列表发送回GUI线程以在那里进行处理,我担心它将如何处理。 Basically, in the worker thread, I have a loop that will fill up the list, send it back to the GUI via an event handler, and then clear it so it can fill it up on the next pass through the loop and start again. 基本上,在工作线程中,我有一个循环,该循环将填充列表,通过事件处理程序将其发送回GUI,然后清除它,以便在下一次通过循环时将其填充并重新开始。

I am worried that when I do this, if the list is passed by reference, then on the UI thread, I would think that it would be cleared mid-read since the worker thread will still be clearing it in the background. 我担心这样做时,如果列表是通过引用传递的,那么在UI线程上,我会认为它会在读取过程中被清除,因为工作线程仍会在后台清除它。 Passing by would be far preferable in this case, and I can find ways to force it(copy to some holder array or add a mutex or something of the sort), but I thought it would be good to know if event arguments are passed via reference or value in general, or is it just the same as methods, and it will pass them as arguments are normally passed? 在这种情况下,通过将是更可取的,我可以找到强制它的方法(复制到某个holder数组或添加互斥锁或类似的东西),但是我认为最好知道是否通过通常是引用或值,还是与方法相同,并且将在通常传递参数时传递给它们?

I know that some values are passed via value (like int and long), and others are passed by reference (like Strings) when you pass them to functions. 我知道有些值是通过值传递的(如int和long),而有些值是通过引用传递的(如Strings),当您将它们传递给函数时。

Nope. 不。 By default everything is passed by value - but when you're using reference types, the "everything" is a reference. 默认情况下,所有内容都按值传递-但是,当您使用引用类型时,“所有内容”都是引用。 That reference is passed by value. 该引用按值传递。 That's not the same as pass by reference. 那是一样的按引用传递。 See my article on parameter passing for more details. 有关更多详细信息,请参见我的有关参数传递的文章

Event arguments are exactly the same - any references are passed by value, assuming the corresponding delegate doesn't use out or ref parameters. 事件参数完全相同-假设相应的委托不使用outref参数,则所有引用均按值传递。

EDIT: So to address your concern: yes, if your event argument is mutable and you're going to act on a different thread, you should create a copy first... or alternatively, pass the existing reference and then create a new (empty) list in your worker thread. 编辑:因此,为了解决您的问题:是的,如果您的事件参数是可变的,并且您打算在其他线程上执行操作,则应首先创建一个副本...或者通过现有的引用,然后创建一个新的(空)列表中的工作线程。

Arguments themselves are passed by value by default. 默认情况下,参数本身按值传递。 However, depending on their type, they can be values or references to the actual values you're working with. 但是,根据它们的类型,它们可以是值或对您正在使用的实际值的引用。

Note that this is not the same as what is commonly known as passing by reference , as the very value actually passed to an argument is copied (ie passed by value ). 请注意,这与通常称为“ 按引用传递”不同 ,因为实际上传递给参数的值是复制的(即按值传递 )。 However, the effect is similar in that if you change the referenced object within the method, the changes will be visible outside of the method (in the code where you invoked the method), too. 但是,其效果类似,因为如果您在方法内更改了引用的对象,则更改也将在方法外部(在调用该方法的代码中)可见。

Now, when passing by value, there is nothing special about event arguments; 现在,按值传递时,事件参数没有什么特别的。 whether the values are copied or only their references entirely depends on their type. 值是被复制还是仅它们的引用完全取决于它们的类型。 So, as you said, int and long arguments (and some more, any struct types) are value types, while others like string (and any class instances) are reference types. 因此,正如您所说, intlong参数(还有更多的任何struct类型)是值类型,而诸如string (以及任何类实例)之类的其他参数都是引用类型。

Note that a true passing by reference is possible in C#, too, but that requires the ref keyword . 请注意,在C#中也可以通过引用进行真正的传递 ,但这需要ref关键字

In the standard event pattern there are two references passed in: 在标准事件模式中,传入了两个引用:

 void FormClosing(object sender, FormClosingEventArgs e) { ... }

those two references are passed 'by value', using for example sender = null will have no effect outside the handling method. 这两个引用“按值”传递,例如使用sender = null将在处理方法之外sender = null

But you can easily pass a value back: 但是您可以轻松地传递一个值:

void FormClosing(object sender, FormClosingEventArgs e)
{
    ...
    e.Cancel = true;  // this will pass back to the caller
}

The event arguments are passed according to the type of the arguments and the signature of the event handler's delegate ( in , out or ref) - if it is a class, then a copy of the reference is passed, if it is a struct, then the copy of the value is passed (assuming signature does not specify out or ref). 根据参数的类型事件处理程序的委托人的签名in ,out或ref)传递事件参数-如果是类,则传递引用的副本,如果是结构,则传递传递值的副本(假设签名未指定out或ref)。

The event arguments are usually a class (usually inherits from EventArgs ) and are often used to return values such as eventArgs.DoCancel to the caller. 事件参数通常是一个类(通常从EventArgs继承),通常用于将诸如eventArgs.DoCancel之类的值返回给调用者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM