TK.*_*TK. 851 c# reference ref out keyword
我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改.有什么区别:
public void myFunction(ref MyClass someClass)
Run Code Online (Sandbox Code Playgroud)
和
public void myFunction(out MyClass someClass)
Run Code Online (Sandbox Code Playgroud)
我应该使用哪个以及为什么?
Run*_*tad 1120
ref告诉编译器在进入函数之前初始化对象,同时out告诉编译器该对象将在函数内初始化.
所以虽然ref是双向的,但是out只有出路.
小智 511
该ref修改意味着:
该out修改意味着:
Mic*_*urn 140
让我们说Dom在Peter的小隔间里出现关于TPS报告的备忘录.
如果Dom是一个参考论证,他会有一份备忘录的印刷版.
如果Dom是一个争吵,他会让彼得打印一份备忘录的新副本供他随身携带.
Jam*_*and 53
我将试着解释一下:
我想我们理解价值类型是如何运作的?值类型是(int,long,struct等).当您将它们发送到没有ref命令的函数时,它会复制数据.您在函数中对该数据执行的任何操作仅影响副本,而不影响原始副本.ref命令发送ACTUAL数据,任何更改都将影响函数外部的数据.
好的混淆部分,参考类型:
让我们创建一个引用类型:
List<string> someobject = new List<string>()
Run Code Online (Sandbox Code Playgroud)
当你新建某个对象时,会创建两个部分:
现在,当你在发送someobject成方法,无需裁判它复制引用指针,而不是数据.所以你现在有这个:
(outside method) reference1 => someobject
(inside method) reference2 => someobject
Run Code Online (Sandbox Code Playgroud)
两个引用指向同一个对象.如果使用reference2 修改someobject上的属性,它将影响reference1指向的相同数据.
(inside method) reference2.Add("SomeString");
(outside method) reference1[0] == "SomeString" //this is true
Run Code Online (Sandbox Code Playgroud)
如果将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
Run Code Online (Sandbox Code Playgroud)
现在,当您通过引用方法发送someobject时会发生什么?在实际的参考,以someobject被发送到该方法.所以你现在只有一个数据引用:
(outside method) reference1 => someobject;
(inside method) reference1 => someobject;
Run Code Online (Sandbox Code Playgroud)
但是,这是什么意思?除了两个主要内容之外,它与发送某些对象的行为完全相同:
1)当你在方法中取消引用时,它将使方法外的引用为空.
(inside method) reference1 = null;
(outside method) reference1 == null; //true
Run Code Online (Sandbox Code Playgroud)
2)您现在可以将引用指向完全不同的数据位置,并且函数外部的引用现在将指向新的数据位置.
(inside method) reference1 = new List<string>();
(outside method) reference1.Count == 0; //this is true
Run Code Online (Sandbox Code Playgroud)
Naz*_*san 18
在C#中,方法只能返回一个值.如果您想返回多个值,可以使用out关键字.out修饰符返回引用返回值.最简单的答案是关键字"out"用于从方法中获取值.
在C#中,当您传递一个值类型(如int,float,double等)作为方法参数的参数时,它将按值传递.因此,如果修改参数值,则不会影响方法调用中的参数.但是如果用"ref"关键字标记参数,它将反映在实际变量中.
小智 13
扩展狗,猫的例子.使用ref的第二个方法更改调用者引用的对象.因此"猫"!!!
public static void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Dog".
Bar(ref myObject);
Console.WriteLine(myObject.Name); // Writes "Cat".
}
public static void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
public static void Bar(ref MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
Run Code Online (Sandbox Code Playgroud)
由于您传入的是引用类型(类),因此无需使用,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";
}
Run Code Online (Sandbox Code Playgroud)
只要您ref想要更改方法中的对象,只要传入一个类就不必使用.
ref并且out表现相似,除了以下差异.
ref变量必须在使用前初始化.out变量可以不经赋值使用out必须将参数视为使用它的函数的未分配值.因此,我们可以out在调用代码中使用初始化参数,但是当函数执行时该值将丢失.对于那些通过实例学习的人(像我一样),这就是Anthony Kolesov所说的.
我已经创建了一些ref,out和其他的最小例子来说明这一点.我没有介绍最佳实践,仅仅是了解差异的例子.
https://gist.github.com/2upmedia/6d98a57b68d849ee7091
"贝克"
那是因为第一个将你的字符串引用更改为指向"Baker".可以更改引用,因为您通过ref关键字(=>对字符串引用的引用)传递了引用.第二个调用获取对字符串的引用的副本.
字符串起初看起来有些特殊.但是string只是一个引用类,如果你定义的话
string s = "Able";
Run Code Online (Sandbox Code Playgroud)
然后s是对包含文本"Able"的字符串类的引用!通过相同变量的另一个赋值
s = "Baker";
Run Code Online (Sandbox Code Playgroud)
不会更改原始字符串,只是创建一个新实例,让我们指向该实例!
您可以使用以下小代码示例尝试:
string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);
Run Code Online (Sandbox Code Playgroud)
你能指望什么?你将获得的仍然是"Able",因为你只是将s中的引用设置为另一个实例,而s2指向原始实例.
编辑:字符串也是不可变的,这意味着根本没有修改现有字符串实例的方法或属性(你可以尝试在文档中找到一个,但你不会吝啬任何:-)).所有字符串操作方法都返回一个新的字符串实 (这就是为什么在使用StringBuilder类时经常获得更好的性能)
Out: return语句只能用于从函数中返回一个值。但是,使用输出参数,您可以从函数返回两个值。输出参数类似于参考参数,不同之处在于它们将数据从方法中传输出来而不是传输到方法中。
以下示例说明了这一点:
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void getValue(out int x )
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
Console.WriteLine("Before method call, value of a : {0}", a);
/* calling a function to get the value */
n.getValue(out a);
Console.WriteLine("After method call, value of a : {0}", a);
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
ref: 引用参数是对变量的存储位置的引用。当您通过引用传递参数时,与值参数不同,不会为这些参数创建新的存储位置。参考参数表示与提供给该方法的实际参数相同的存储位置。
在C#中,使用ref关键字声明参考参数。下面的示例演示了这一点:
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void swap(ref int x, ref int y)
{
int temp;
temp = x; /* save the value of x */
x = y; /* put y into x */
y = temp; /* put temp into y */
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
int b = 200;
Console.WriteLine("Before swap, value of a : {0}", a);
Console.WriteLine("Before swap, value of b : {0}", b);
/* calling a function to swap the values */
n.swap(ref a, ref b);
Console.WriteLine("After swap, value of a : {0}", a);
Console.WriteLine("After swap, value of b : {0}", b);
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
ref表示ref参数中的值已设置,该方法可以读取和修改它。使用ref关键字与说调用方负责初始化参数的值相同。
out告诉编译器,对象的初始化是函数的责任,该函数必须分配给out参数。不允许将其保留为未分配状态。
除了允许您将其他人的变量重新分配给类的不同实例、返回多个值等之外,还可以使用ref或out让其他人知道您需要他们提供什么以及您打算如何处理他们提供的变量
您不需要 ref,或者out如果您要做的只是修改参数中传递的实例内的内容。MyClasssomeClass
someClass.Message = "Hello World"您是否使用ref,out或什么都不使用someClass = new MyClass()内部会交换出仅在方法范围内myFunction(someClass)看到的对象。调用方法仍然知道它创建并传递给您的方法的原始实例someClassmyFunctionMyClass您需要 ref或者out如果您计划将其替换someClass为一个全新的对象并希望调用方法看到您的更改
someClass = new MyClass()在内部写入myFunction(out someClass)会更改调用方法所看到的对象myFunction他们想知道你将如何处理他们的数据。想象一下您正在编写一个将被数百万开发人员使用的库。您希望他们知道当他们调用您的方法时您将如何处理他们的变量
使用ref声明“当您调用我的方法时,传递一个分配给某个值的变量。请注意,我可能会在我的方法过程中将其完全更改为其他内容。不要期望您的变量指向旧对象当我完成时”
usingout声明了“向我的方法传递一个占位符变量。它是否有值并不重要;编译器会强制我将它赋给一个新值。我绝对保证你所指向的对象在调用我的方法之前的变量,在我完成时会有所不同
in修饰符这可以防止该方法将传入的实例交换为不同的实例。可以将其视为对数百万开发人员说“将您的原始变量引用传递给我,我保证不会将您精心制作的数据交换为其他内容”。in有一些特殊性,在某些情况下,例如可能需要隐式转换以使您的short与int兼容,in int编译器将暂时创建一个int,将您的short扩展到它,通过引用传递它并完成。它可以做到这一点,因为你已经声明你不会搞乱它。
微软.TryParse通过数字类型的方法做到了这一点:
int i = 98234957;
bool success = int.TryParse("123", out i);
Run Code Online (Sandbox Code Playgroud)
通过标记参数,因为out他们在这里主动声明“我们肯定会将您精心设计的值 98234957 更改为其他值”
当然,对于解析值类型之类的事情,他们有点必须这样做,因为如果不允许解析方法将值类型交换为其他内容,那么它就不会很好地工作。但是想象一下,在某些情况下有一些虚构的方法您正在创建的库:
public void PoorlyNamedMethod(out SomeClass x)
Run Code Online (Sandbox Code Playgroud)
你可以看到它是一个out,因此你可以知道,如果你花几个小时处理数字,创建完美的 SomeClass:
SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);
Run Code Online (Sandbox Code Playgroud)
好吧,那是浪费时间,花那么多时间来上完美的课。它肯定会被扔掉并被 PoorlyNamedMethod 取代
对于那些寻找简洁答案的人。
这两个
ref和out关键字用于通过逐reference。
ref关键字变量必须有一个值或必须引用一个对象或null在它传递之前。
与 不同
ref,out关键字的变量必须有值或必须引用一个对象或null在它传递之后,并且在传递之前不需要有值或引用一个对象。
| 归档时间: |
|
| 查看次数: |
370417 次 |
| 最近记录: |