“有什么用?”;参考「;对于C#中的引用类型变量?
我知道,如果我将值类型(“有什么用?”;参考「;对于C#中的引用类型变量?,c#,parameters,pass-by-reference,pass-by-value,C#,Parameters,Pass By Reference,Pass By Value,我知道,如果我将值类型(int,struct等)作为参数传递(没有ref关键字),该变量的副本将传递给方法,但如果我使用ref关键字,则传递对该变量的引用,而不是新的引用 但是对于引用类型,比如类,即使没有ref关键字,也会将引用传递给方法,而不是副本。那么ref关键字与引用类型有什么关系呢 例如: var x = new Foo(); 以下两者之间的区别是什么 void Bar(Foo y) { y.Name = "2"; } 及 在某些情况下,您需要修改实际的参考,而不是指向的
int
,struct
等)作为参数传递(没有ref
关键字),该变量的副本将传递给方法,但如果我使用ref
关键字,则传递对该变量的引用,而不是新的引用
但是对于引用类型,比如类,即使没有ref
关键字,也会将引用传递给方法,而不是副本。那么ref
关键字与引用类型有什么关系呢
例如:
var x = new Foo();
以下两者之间的区别是什么
void Bar(Foo y) {
y.Name = "2";
}
及
在某些情况下,您需要修改实际的参考,而不是指向的对象:
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]);
void Swap(参考T x,参考T y){
T=x;
x=y;
y=t;
}
var test=new[]{“0”,“1”};
交换(参考测试[0],参考测试[1]);
您可以使用y
更改foo
指向的内容:
Foo foo = new Foo("1");
void Bar(ref Foo y)
{
y = new Foo("2");
}
Bar(ref foo);
// foo.Name == "2"
它允许您修改传入的引用。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();
}
如果不关心传入的引用,也可以使用out:
void Bar()
{
var y = new Foo();
Baz(out y);
}
void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}
当您传递带有ref关键字的引用类型时,您将逐个引用传递引用,并且您调用的方法可以为参数指定一个新值。该更改将传播到调用范围。如果没有ref,引用将按值传递,而这不会发生 C#也有'out'关键字,它与ref非常相似,除了'ref'的参数必须在调用方法之前初始化,而'out'的参数必须在接收方法中赋值。另一组代码
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;
}
}
Jon Skeet写了一篇关于C#中的参数传递的文章。它清楚地详细说明了按值、按引用(ref
)和按输出(out
)传递参数的确切行为和用法
以下是该页中有关ref
参数的重要引用:
引用参数不通过
中使用的变量的值
函数成员调用-它们使用
变量本身。而不是
为创建新的存储位置
函数成员中的变量
声明,相同的存储位置
已使用,因此变量的值
在函数成员和值中
引用参数的
都一样。参考参数需要
ref修饰符作为
声明和调用-即
这意味着当你
通过引用传递某物
这里有很好的解释: 文章摘要: 引用类型的变量不直接包含其数据;信息技术 包含对其数据的引用。当传递引用类型时 参数的值,可以更改 引用,例如类成员的值。然而,你 无法更改引用本身的值;也就是说,你不能 使用相同的引用为一个新类分配内存,并将其保存 坚持在街区之外。为此,请使用 ref或out关键字
方法中的参数似乎总是传递一个副本,问题是什么的副本。复制是由对象的复制构造函数完成的,因为所有变量都是C#中的对象,所以我相信所有变量都是这样。变量(对象)类似于居住在某些地址的人。我们要么改变住在这些地址的人,要么在电话簿中创建更多关于住在这些地址的人的引用(制作浅显副本)。因此,多个标识符可以引用同一地址。引用类型需要更多的空间,因此与通过箭头直接连接到堆栈中标识符的值类型不同,它们具有堆中另一个地址的值(更大的驻留空间)。这个空间需要从堆中获取 值类型: 标识符(包含值=堆栈值的地址)--->值类型的值 参考类型: 标识符(包含值=堆栈值的地址)--->(包含值=堆值的地址)--->堆值(通常包含指向其他值的地址),想象更多指向数组[0]、数组[1]、数组[2]不同方向的箭头
更改值的唯一方法是跟随箭头。如果一个箭头丢失/更改,则无法访问该值 除现有答案外: 当您询问两种方法的差异时:使用
ref
或out
时,没有co(ntra)差异:
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
}
引用变量将地址从一个地方传递到另一个地方,因此在任何地方对其进行的任何更新都将反映在所有地方,那么REF的用途是什么呢。 参考变量(405)在没有为方法中传递的参考变量分配新内存之前是良好的 一旦分配了新的内存(410),那么该对象(408)上的值更改将不会反映到任何地方。 这个裁判来了。Ref是reference的reference,因此每当分配新内存时,它都会知道,因为它指向该位置,因此每个人都可以共享该值。你可以看到更清晰的图像
所以你基本上得到了对原始参考的引用。你可以改变原始参考“引用”的内容,所以是的。克里斯,你的解释很好;谢谢你帮助我理解这个概念。所以在一个对象上使用“REF”就像使用C++中的双指针?@ TimHaZel:-ISH,如果你用C++中的“双”指针来改变指针指向什么。我喜欢把你的狗皮带传给朋友,以通过值传递引用。但它很快就崩溃了,因为我想你可能会注意到,如果你的朋友在把皮带还给你之前把你的狗屎换成了杜宾;-)这个解释确实很好。然而,不鼓励只提供链接的答案。为了方便阅读,我添加了文章的摘要
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
}