Rya*_*yan 269 .net c# ref pass-by-reference
如果我将对象传递给方法,为什么要使用ref关键字?这不是默认行为吗?
例如:
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t.Something = "Bar";
}
}
public class TestRef
{
public string Something { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
输出为"Bar",表示该对象作为参考传递.
Sco*_*ham 282
ref
如果要更改对象的内容,请传递a :
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
Run Code Online (Sandbox Code Playgroud)
在调用DoSomething之后,t
不是指原始的new TestRef
,而是指一个完全不同的对象.
如果要更改不可变对象的值,这也可能很有用,例如a string
.string
一旦创建,您就无法更改它的值.但是通过使用a ref
,您可以创建一个函数来更改另一个具有不同值的字符串.
编辑:正如其他人提到的那样.ref
除非需要,否则使用它不是一个好主意.使用ref
赋予方法自由更改其他内容的参数,方法的调用者将需要编码以确保它们处理这种可能性.
此外,当参数类型是对象时,对象变量始终充当对象的引用.这意味着当使用ref
关键字时,您已获得对引用的引用.这允许您执行上面给出的示例中描述的操作.但是,当参数类型是原始值(例如int
)时,如果在方法中指定了此参数,则在方法返回后将传入的参数值将更改:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 87
您需要区分"按值传递引用"和"通过引用传递参数/参数".
我已经写了一篇相当长的关于这个主题的文章,以避免每次出现在新闻组时都要小心写:)
Ric*_*res 51
在.NET中,当您将任何参数传递给方法时,都会创建一个副本.在值类型中,表示对值进行的任何修改都在方法范围内,并在退出方法时丢失.
传递引用类型时,也会创建一个副本,但它是引用的副本,即现在内存中有两个对同一对象的引用.因此,如果使用引用来修改对象,则会对其进行修改.但是如果您修改引用本身 - 我们必须记住它是一个副本 - 那么在退出该方法时也会丢失任何更改.
正如人们之前所说的那样,赋值是对引用的修改,因此丢失了:
public void Method1(object obj) {
obj = new Object();
}
public void Method2(object obj) {
obj = _privateObject;
}
Run Code Online (Sandbox Code Playgroud)
上述方法不会修改原始对象.
对你的例子进行一点修改
using System;
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t = new TestRef();
t.Something = "Bar";
}
}
public class TestRef
{
private string s;
public string Something
{
get {return s;}
set { s = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
Fer*_*cio 17
由于TestRef是一个类(它们是引用对象),因此您可以更改t中的内容而不将其作为引用传递.但是,如果将t作为ref传递,则TestRef可以更改原始t所指的内容.即使它指向不同的对象.
Rin*_*lin 15
随ref
你可以写:
static public void DoSomething(ref TestRef t)
{
t = new TestRef();
}
Run Code Online (Sandbox Code Playgroud)
方法完成后,t将被更改.
foo
将引用类型的变量(例如)List<T>
视为(例如)作为"对象#24601"形式的保持对象标识符.假设该语句foo = new List<int> {1,5,7,9};
导致foo
持有"对象#24601"(包含四个项目的列表).然后调用foo.Length
将询问对象#24601的长度,它将响应4,因此foo.Length
将等于4.
如果foo
传递给不使用的方法ref
,则该方法可能会对对象#24601进行更改.由于这些变化,foo.Length
可能不再等于4.然而,方法本身将无法更改foo
,这将继续保持"对象#24601".
foo
作为ref
参数传递将允许被调用的方法不仅对对象#24601进行更改,而且对foo
自身进行更改.该方法可能会创建一个新的对象#8675309并存储对其的引用foo
.如果它这样做,foo
将不再持有"对象#24601",而是"对象#8675309".
实际上,引用类型变量不包含"Object#8675309"形式的字符串; 他们甚至没有任何可以有意义地转换成数字的东西.尽管每个引用类型变量将保持一些位模式,但存储在这些变量中的位模式与它们识别的对象之间没有固定的关系.代码无法从对象或对它的引用中提取信息,并且稍后确定另一个引用是否标识了相同的对象,除非代码保持或知道标识原始对象的引用.