我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:
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可以让别人知道你需要从他们那里得到什么,以及你打算用他们提供的变量做什么
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修饰符的意思是:
该值已经设置,并且 该方法可以读取和修改它。
out修饰符的意思是:
Value未被设置,并且在设置之前不能被方法读取。 方法必须在返回之前设置它。
我要试着解释一下:
我想我们理解了值类型是如何工作的,对吧?值类型是(int, long, struct等)。当你将它们发送到一个没有ref命令的函数时,它会复制数据。在函数中对该数据所做的任何操作都只会影响副本,而不会影响原始数据。ref命令发送的是实际数据,任何变化都会影响函数外部的数据。
好了,让人困惑的部分,引用类型:
让我们创建一个引用类型:
List<string> someobject = new List<string>()
当你新建someobject时,会创建两部分:
存储某对象数据的内存块。 指向该块的引用(指针) 的数据。
现在,当你发送someobject到一个没有引用的方法时,它复制的是引用指针,而不是数据。现在你得到了这个:
(outside method) reference1 => someobject
(inside method) reference2 => someobject
两个引用指向同一个对象。如果你使用reference2修改某个对象的属性,它将影响由reference1指向的相同数据。
(inside method) reference2.Add("SomeString");
(outside method) reference1[0] == "SomeString" //this is true
如果你清空了reference2或将其指向新的数据,它不会影响reference1和reference1所指向的数据。
(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true
The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject
当你将someobject by ref发送给方法时会发生什么? 对某个对象的实际引用被发送给方法。所以你现在只有一个数据引用:
(outside method) reference1 => someobject;
(inside method) reference1 => someobject;
但这意味着什么呢?它的作用与不通过ref发送someobject完全相同,除了两件主要的事情:
1)当你清空方法内部的引用时,它也会清空方法外部的引用。
(inside method) reference1 = null;
(outside method) reference1 == null; //true
2)你现在可以将引用指向一个完全不同的数据位置,函数外部的引用现在将指向新的数据位置。
(inside method) reference1 = new List<string>();
(outside method) reference1.Count == 0; //this is true
out:
在c#中,一个方法只能返回一个值。如果希望返回多个值,可以使用out关键字。out修饰符返回为return-by-reference。最简单的答案是使用关键字“out”从方法中获取值。
您不需要在调用函数中初始化该值。 必须在被调用的函数中赋值,否则编译器将报错。
ref:
在c#中,当你将一个值类型,如int, float, double等作为参数传递给方法参数时,它是按值传递的。因此,如果修改形参值,它不会影响方法调用中的实参。但是,如果您用“ref”关键字标记参数,它将反映在实际的变量中。
在调用函数之前,需要初始化变量。 为方法中的ref参数赋值不是强制的。如果不更改值,为什么需要将其标记为“ref”?
迟了回答,但想到了发帖。可能比其他答案更清楚一点。
ref的关键字:
ref is a keyword which is used to pass any value by reference(refer to call by value and call by reference in programming for further knowledge). In short, you declare and initialize a value for example let us say int age = 5; so this age is saved in the memory by holding a place of 4 bytes. Now if you are passing this age variable to another method with ref (which means passing them by reference and not by value) then the compiler will just pass the reference of that variable or in clear terms, the memory address of the place where the variable is stored and the called method receives this address and directly accesses the data in that address. So obviously any change to that data will happen also to the variable present in the calling method.
示例:我提供了我的stackoverflow帐户的密码并告诉他 他可以做任何他想做的事,他可以提问或回答。的 问题是,他做的任何改变都会直接影响到我的账户。
关键字:
Out和in类似于它们都传递变量的引用。现在我们知道,两者都需要传递变量的引用,很明显,内存中必须有一个地方保存变量的字节。但在out的情况下没有初始化。因为要求是,被调用的方法必须初始化值并返回它。
示例:我将stackoverflow站点地址发送给我的朋友并询问 让他帮我开个账户,把证件还给我。
关键字:
现在,in关键字的工作原理与ref关键字完全相同,只有一个条件,即作为引用传递的值不能被修改。
示例:我提供了我的stackoverflow帐户的密码,但告诉了他 不做任何事情,除了阅读或浏览网站。不要问 问题,没有答案,没有投票,什么都没有。
MSDN引用:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier
希望以上说明清楚了。
由于您传递的是引用类型(类),因此不需要使用ref,因为默认情况下只传递对实际对象的引用,因此您总是要更改引用后面的对象。
例子:
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Cat".
}
public void Bar(MyClass someObject)
{
someObject.Name = "Cat";
}
只要传入一个类,如果你想在方法中改变对象,就不必使用ref。