我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
public void myFunction(ref MyClass someClass)
and
public void myFunction(out MyClass someClass)
我应该用哪个,为什么?
我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
public void myFunction(ref MyClass someClass)
and
public void myFunction(out MyClass someClass)
我应该用哪个,为什么?
当前回答
Ref告诉编译器对象在进入函数之前已经初始化,而out告诉编译器对象将在函数内部初始化。
所以当ref是双向的,out是唯一的。
其他回答
对于那些以身作则的人(比如我),以下是安东尼·科索夫所说的。
我创建了一些ref、out和其他例子来说明这一点。我并没有介绍最佳实践,只是举例来理解它们之间的差异。
https://gist.github.com/2upmedia/6d98a57b68d849ee7091
创作时间:
我们创建调用方法Main()
(2)它创建一个List对象(这是一个引用类型对象)并将其存储在变量myList中。
public sealed class Program
{
public static Main()
{
List<int> myList = new List<int>();
在运行时:
(3)运行时在堆栈#00处分配一个内存,足够宽来存储一个地址(#00 = myList,因为变量名实际上只是内存位置的别名)
(4)运行时在内存位置#FF的堆上创建一个列表对象(所有这些地址都是为了举例)
(5) Runtime会将对象的起始地址#FF存储在#00(或者在word中,将List对象的引用存储在指针myList中)
回到创作时间:
(6)然后我们将List对象作为参数myParamList传递给被调用的方法modifyMyList,并将一个新的List对象赋给它
List<int> myList = new List<int>();
List<int> newList = ModifyMyList(myList)
public List<int> ModifyMyList(List<int> myParamList){
myParamList = new List<int>();
return myParamList;
}
在运行时:
(7)运行时启动被调用方法的调用例程,作为它的一部分,检查参数的类型。
(8)在找到引用类型后,它在堆栈#04处分配一个内存,用于别名参数变量myParamList。
然后它将值#FF也存储在其中。
(10) Runtime在内存位置#004的堆上创建一个列表对象,并用这个值替换#04中的#FF(或者在这个方法中取消引用原始的list对象并指向新的list对象)
#00中的地址不会改变,并保留对#FF的引用(或者原始的myList指针不会被干扰)。
ref关键字是一个编译器指令,用于跳过(8)和(9)的运行时代码的生成,这意味着不会为方法参数分配堆。它将使用原始的#00指针对位于#FF的对象进行操作。如果原始指针没有初始化,运行时将停止抱怨它不能继续,因为变量没有初始化
out关键字是一个编译器指令,它与ref几乎相同,只是在(9)和(10)处略有修改。编译器期望参数是未初始化的,并将继续使用(8),(4)和(5)在堆上创建一个对象,并将其起始地址存储在参数变量中。不会抛出任何未初始化的错误,并且之前存储的任何引用都将丢失。
简洁的回答。
ref和out关键字都用于引用传递。 关键字为ref的变量必须有一个值或必须引用一个对象 或者在它传递之前为null。 与ref不同,关键字为out的变量必须有一个值或必须 在对象传递后引用对象或null以及不需要 在传递之前有一个值或引用一个对象。
除了允许你将别人的变量重新分配给类的不同实例,返回多个值等,使用ref或out可以让别人知道你需要从他们那里得到什么,以及你打算用他们提供的变量做什么
You don't need ref or out if all you're going to do is modify things inside the MyClass instance that is passed in the argument someClass. The calling method will see changes like someClass.Message = "Hello World" whether you use ref, out or nothing Writing someClass = new MyClass() inside myFunction(someClass) swaps out the object seen by the someClass in the scope of the myFunction method only. The calling method still knows about the original MyClass instance it created and passed to your method You need ref or out if you plan on swapping the someClass out for a whole new object and want the calling method to see your change Writing someClass = new MyClass() inside myFunction(out someClass) changes the object seen by the method that called myFunction
还有其他程序员
他们想知道你将如何处理他们的数据。假设您正在编写一个将被数百万开发人员使用的库。你想让他们知道当他们调用你的方法时你要对他们的变量做什么
Using ref makes a statement of "Pass a variable assigned to some value when you call my method. Be aware that I might change it out for something else entirely during the course of my method. Do not expect your variable to be pointing to the old object when I'm done" Using out makes a statement of "Pass a placeholder variable to my method. It doesn't matter whether it has a value or not; the compiler will force me to assign it to a new value. I absolutely guarantee that the object pointed to by your variable before you called my method, will be different by the time I'm done
顺便说一下,在c# 7.2中也有一个in修饰符
And that prevents the method from swapping out the passed in instance for a different instance. Think of it like saying to those millions of developers "pass me your original variable reference, and I promise not to swap your carefully crafted data out for something else". in has some peculiarities, and in some cases such as where an implicit conversion might be required to make your short compatible with an in int the compiler will temporarily make an int, widen your short to it, pass it by reference and finish up. It can do this because you've declared you're not going to mess with it.
微软对数值类型的.TryParse方法做到了这一点:
int i = 98234957;
bool success = int.TryParse("123", out i);
通过将参数标记为out他们在这里积极地声明"我们肯定会将你苦心制作的98234957值更改为其他值"
当然,对于像解析值类型这样的事情,它们有点不得不这样做,因为如果parse方法不允许将值类型替换为其他类型,那么它就不能很好地工作。但是想象一下在你创建的库中有一些虚构的方法:
public void PoorlyNamedMethod(out SomeClass x)
你可以看到它是一个out,因此你可以知道,如果你花了几个小时处理数字,创建一个完美的SomeClass:
SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);
那真是浪费时间,花那么多时间来做一节完美的课。它肯定会被丢弃,并被PoorlyNamedMethod取代
Ref表示Ref参数中的值已经设置,方法可以读取和修改它。 使用ref关键字等同于说调用方负责初始化形参的值。
Out告诉编译器,对象的初始化是由 函数需要赋值给out形参。 没有分配是不允许的。
https://www.codemaggot.com/ref-and-out-keywords/