大家好,
我很惊讶为什么我们在C#中有ref
,而默认情况下,C#中的所有引用类型都作为参考传递。
简单来说,任何人都可以解释这两种方法调用之间的区别:
public void Test(SomeClass someClass)
{
// some code here
}
和
public void Test(ref SomeClass someClass)
{
// some code here
}
在我看来,他们都参考了相同的记忆位置。
那么为什么我们需要ref
个关键字?
答案 0 :(得分:8)
ref
关键字传递对存储引用的任何位置的引用。这允许您从被调用函数中操作此变量。这对于值类型特别有用,但在与引用类型一起使用时也有用。 (Dictionary.TryGetValue()
是一个很好的例子。out
参数是返回存储在字典中的值所必需的。out
相当于ref
,除了它将经历一个不同的集合编译时检查。)
例如:
public void Test(ref SomeClass obj)
{
obj = null;
}
public void Test2(SomeClass obj)
{
obj = null;
}
public void Foo()
{
SomeClass obj = new SomeClass();
Test(ref obj);
// obj is null here!
obj = new SomeClass();
Test2(obj);
// obj is not null here.
}
答案 1 :(得分:3)
我很惊讶为什么我们在C#中使用ref,而默认情况下,C#中的所有引用类型都作为引用传递。
因为C#中的某些东西是值类型,有时我们想要传递它们。我们有ref
关键字,以便这些内容也可以通过引用传递。
答案 2 :(得分:3)
这类似于C ++中SomeClass *
和SomeClass **
之间的差异。
使用SomeClass *
(或没有ref
),我们可以修改指向的对象,但我们无法将其重定向到一个全新的对象。
使用SomeClass **
(或ref
),我们可以更改调用代码中的参数,以便将其指向我们选择的对象。
答案 3 :(得分:2)
传递对象时,通过引用传递它。这意味着在该方法返回后,您对该对象所做的任何操作都将反映在该对象中。当您通过引用传递引用,即void Foo(ref object obj)
时,您将传递该对象的地址。然后,您可以将地址重新分配给另一个对象,这将是方法返回时的状态
foo (object o)
{
...
}
var v = new object();
foo(v);
v
仍将引用在调用foo之前实例化的同一对象
void bar(ref object o)
{
o = null;
}
var v = new object();
foo(ref v);
// v is now null
答案 4 :(得分:0)
假设方法Foo按值接受Bar。如果我有一个名为“Boz”的栏,声明:
Foo(Boz);
可以使用Boz指向的对象并更改该对象的特征,但它不能更改 Boz指向的对象。相比之下,如果Boz通过引用传递,相同的语句可能会导致Boz完全指向不同的对象。
作为使用示例,请考虑接受数组作为参数的例程。如果按值传递数组,则收件人可以更改数组中任何项的值,但收件人无法更改大小。更改数组大小的唯一方法是创建一个新数组,将旧项复制到其中,然后使用新数组而不是旧数组。当一个数组按值传递时,收件人无法告诉调用者它应该停止使用旧数组并使用新数组。使用引用传递的数组不是问题。