C#中引用类型变量的“ref”有什么用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/961717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the use of "ref" for reference-type variables in C#?
提问by Andreas Grech
I understand that if I pass a value-type (int
, struct
, etc.) as a parameter (without the ref
keyword), a copy of that variable is passed to the method, but if I use the ref
keyword a reference to that variable is passed, not a new one.
我明白,如果我将值类型(int
、struct
等)作为参数(不带ref
关键字)传递,则该变量的副本将传递给该方法,但如果我使用该ref
关键字,则会传递对该变量的引用,不是新的。
But with reference-types, like classes, even without the ref
keyword, a reference is passed to the method, not a copy. So what is the use of the ref
keyword with reference-types?
但是对于引用类型,如类,即使没有ref
关键字,也会将引用传递给方法,而不是副本。那么ref
关键字和引用类型有什么用呢?
Take for example:
举个例子:
var x = new Foo();
What is the difference between the following?
以下有什么区别?
void Bar(Foo y) {
y.Name = "2";
}
and
和
void Bar(ref Foo y) {
y.Name = "2";
}
采纳答案by user7116
You can change what foo
points to using y
:
您可以更改foo
要使用的内容y
:
Foo foo = new Foo("1");
void Bar(ref Foo y)
{
y = new Foo("2");
}
Bar(ref foo);
// foo.Name == "2"
回答by Mehrdad Afshari
There are cases where you want to modify the actual referenceand not the object pointed to:
在某些情况下,您要修改实际引用而不是指向的对象:
void Swap<T>(ref T x, ref T y) {
T t = x;
x = y;
y = t;
}
var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);
回答by Hans Van Slooten
It allows you to modify the reference passed in. e.g.
它允许您修改传入的引用。例如
void Bar()
{
var y = new Foo();
Baz(ref y);
}
void Baz(ref Foo y)
{
y.Name = "2";
// Overwrite the reference
y = new Foo();
}
You can also use outif you don't care about the reference passed in:
如果您不关心传入的引用,您也可以使用out:
void Bar()
{
var y = new Foo();
Baz(out y);
}
void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}
回答by Rytmis
When you pass a reference type with the ref keyword, you pass the reference by reference, and the method you call can assign a new value to the parameter. That change will propagate to the calling scope. Without ref, the reference is passed by value, and this doesn't happen.
当您使用 ref 关键字传递引用类型时,您是通过引用传递引用,您调用的方法可以为参数分配一个新值。该更改将传播到调用范围。没有 ref,引用是按值传递的,这不会发生。
C# also has the 'out' keyword which is a lot like ref, except that with 'ref', arguments must be initialized before calling the method, and with 'out' you must assign a value in the receiving method.
C#也有'out'关键字,它很像ref,除了'ref',参数必须在调用方法之前初始化,而'out'必须在接收方法中分配一个值。
回答by Svend
Another bunch of code
另一串代码
class O
{
public int prop = 0;
}
class Program
{
static void Main(string[] args)
{
O o1 = new O();
o1.prop = 1;
O o2 = new O();
o2.prop = 2;
o1modifier(o1);
o2modifier(ref o2);
Console.WriteLine("1 : " + o1.prop.ToString());
Console.WriteLine("2 : " + o2.prop.ToString());
Console.ReadLine();
}
static void o1modifier(O o)
{
o = new O();
o.prop = 3;
}
static void o2modifier(ref O o)
{
o = new O();
o.prop = 4;
}
}
回答by Noldorin
Jon Skeet wrote a great articleabout parameter passing in C#. It details clearly the exact behaviour and usage of passing parameters by value, by reference (ref
), and by output (out
).
Jon Skeet 写了一篇关于 C# 中参数传递的精彩文章。它清楚地详细说明了按值、按引用 ( ref
) 和按输出 ( out
)传递参数的确切行为和用法。
Here's an important quote from that page in relation to ref
parameters:
这是该页面中与ref
参数相关的重要引用:
Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference.
引用参数不传递函数成员调用中使用的变量的值 - 它们使用变量本身。而不是在函数成员声明中为变量创建新的存储位置,而是使用相同的存储位置,因此函数成员中变量的值和引用参数的值将始终相同。引用参数需要 ref 修饰符作为声明和调用的一部分——这意味着当你通过引用传递某些东西时总是很清楚的。
回答by himanshupareek66
Very nicely explained here : http://msdn.microsoft.com/en-us/library/s6938f28.aspx
这里很好地解释了:http: //msdn.microsoft.com/en-us/library/s6938f28.aspx
Abstract from the article:
文章摘要:
A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword.
引用类型的变量不直接包含其数据;它包含对其数据的引用。当您按值传递引用类型参数时,可以更改引用指向的数据,例如类成员的值。但是,您不能更改引用本身的值;也就是说,您不能使用相同的引用为新类分配内存并使其在块外持久存在。为此,请使用 ref 或 out 关键字传递参数。
回答by Petar Drianov
A parameter in a method seems to be always passing a copy, the question is a copy of what. A copy is done by a copy constructor for an object and since all variables are Object in C#, i believe this is the case for all of them. Variables(objects) are like people living at some addresses. We either change the people living at those addresses or we can create more references to the people living at those addresses in the phone book(make shallow copies). So, more than one identifier can refer to the same address. Reference types desire more space, so unlike value types that are directly connected by an arrow to their identifier in the stack, they have value for another address in the heap( a bigger space to dwell). This space needs to be taken from the heap.
方法中的参数似乎总是传递一个副本,问题是什么的副本。复制是由对象的复制构造函数完成的,因为所有变量都是 C# 中的对象,我相信所有变量都是这种情况。变量(对象)就像住在某些地址的人。我们要么改变住在这些地址的人,要么我们可以在电话簿中创建更多对住在这些地址的人的引用(制作浅拷贝)。因此,多个标识符可以引用同一个地址。引用类型需要更多空间,因此与通过箭头直接连接到堆栈中的标识符的值类型不同,它们具有堆中另一个地址的值(更大的驻留空间)。这个空间需要从堆中取出。
Value type: Indentifier(contains value =address of stack value)---->Value of value type
值类型:标识符(包含值=栈值地址)---->值类型的值
Reference type: Identifier(contains value=address of stack value)---->(contains value=address of heap value)---->Heap value(most often contains addresses to other values), imagine more arrows sticking in different directions to Array[0], Array[1], array[2]
引用类型:标识符(包含值=堆栈值的地址)---->(包含值=堆值的地址)---->堆值(通常包含指向其他值的地址),想象更多的箭头粘在不同的数组[0]、数组[1]、数组[2]的方向
The only way to change a value is to follow the arrows. If one arrow gets lost/changed in the way the value is unreachable.
更改值的唯一方法是按照箭头操作。如果一个箭头以无法到达的方式丢失/更改。
回答by springy76
In addition to the existing answers:
除了现有的答案:
As you asked for the difference of the 2 methods: There is no co(ntra)variance when using ref
or out
:
当您询问两种方法的区别时:使用ref
or时没有协(ntra)方差out
:
class Foo { }
class FooBar : Foo { }
static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }
void Main()
{
Foo foo = null;
Bar(foo); // OK
Bar(ref foo); // OK
FooBar fooBar = null;
Bar(fooBar); // OK (covariance)
Bar(ref fooBar); // compile time error
}
回答by srbh
Reference Variables carry the address from one place to another so any updation on them at any place will reflect on all the places THEN what is the use of REF. Reference variable (405) are good till no new memory is allocated to the reference variable passed in the method.
引用变量将地址从一个地方带到另一个地方,因此在任何地方对它们的任何更新都会反映在所有地方 THEN REF 的用途是什么。引用变量 (405) 一直有效,直到没有新内存分配给方法中传递的引用变量。
Once new memory allocate (410) then the value change on this object (408) will not reflect everywhere. For this ref comes. Ref is reference of reference so whenever new memory allocate it get to know because it is pointing to that location therefore the value can be shared by everyOne. You can see the image for more clearity.
一旦分配了新内存(410),则此对象(408)上的值更改将不会在任何地方反映出来。对于这个参考来了。Ref 是引用的引用,因此每当新内存分配时,它都会知道,因为它指向该位置,因此每个人都可以共享该值。您可以查看图像以获得更清晰的效果。