请您解释一下C#Class的以下行为。我希望classResult为“Class Lijo”;但实际值是“已更改”。
我们正在制作参考文献的副本。虽然副本指向同一地址,但接收参数的方法不能更改原始地址。
仍然为什么价值会发生变化?
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
String nameString = "string Lijo";
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(nameString, p);
string classResult = p.Name;
Response.Write(nameString + "....." + classResult);
}
}
public class Utilityclass
{
public static void TestMethod(String nameString, Person k)
{
nameString = "Changed";
k.Name = "Changed";
}
}
public class Person
{
public string Name
{
get; set;
}
}
更新:当我传递一个字符串时,它实际上没有被更改。
答案 0 :(得分:22)
最简短的回答是:阅读my article on parameter passing,其中详细介绍了这一点。
稍微长一点的答案是比较这两种方法,两种方法都使用 value 参数:
public void ChangeMe(string x)
{
x = "changed";
}
public void ChangeMe(Person x)
{
x.Name = "changed";
}
在第一种情况下,您要更改参数的值。这与原始论点完全隔离。您无法更改字符串本身的内容,因为字符串是不可变的。
在第二种情况下,您正在更改参数值引用的对象的内容。这并没有改变参数本身的价值 - 它将是相同的参考。举一个现实世界的例子,如果有人向你的房子提供改变房子内容的东西,但它不会改变你家的地址。
如果您将第二种方法更改为:
public void ChangeMe(Person x)
{
x = new Person("Fred");
}
然后调用者不会看到任何变化。这更接近于您对字符串所做的事情 - 您正在使参数引用不同的对象,而不是更改现有对象的内容。
现在,当您使用ref
参数时,调用者用作参数的变量与参数“别名” - 因此,如果更改参数的值,则会更改参数的值同样。所以如果我们改变最后一个方法:
public void ChangeMe(ref Person x)
{
x = new Person("Fred");
}
然后:
Person y = new Person("Eric");
ChangeMe(ref y);
Console.WriteLine(y.Name);
这将打印出“Fred”。
要理解的关键概念是变量的值永远不是对象 - 它可以是值类型值或引用。如果更改了对象的数据,则通过其他引用可以看到该更改。一旦你理解复制一个引用与复制一个对象是不一样的,那么其余部分就会很容易理解。
答案 1 :(得分:7)
Person
是一种引用类型,因此无论您使用ref
,out
还是什么都没有,您始终可以在方法内修改它。您永远不会将真人对象传递给方法,您将指针作为参考传递,而不是实际的Person
。 ref
关键字对值类型(例如,structs,int,float,DateTime,...)非常有用。 它也可以与引用类型一起使用,但仅用于指示行为但不能强制执行它。如果将它与引用类型一起使用,它允许您更改此引用所指向的对象。
答案 2 :(得分:0)
当您将P传递给测试方法时,您将其位置传递到内存中,而不是对象的副本。在方法体中拾取引用并修改原始值。
答案 3 :(得分:0)
Utilityclass.TestMethod
无法将局部变量p
更改为指向不同的Person
对象,因为您没有通过引用传递,但它仍可以自由调用任何方法或更改任何属性在它传递的对象上。因此Name
属性可以在Utilityclass.TestMethod
内修改。
答案 4 :(得分:0)
这个问题已被大部分回答,但我想您可能想试试这个片段(如果您尝试使用整数,可以获得奖励积分!)
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(p);
string classResult = p.Name;
Console.WriteLine(classResult);
Utilityclass.TestMethod2(ref p);
classResult = p.Name; // will bomb here
Console.WriteLine(classResult);
}
}
public class Utilityclass
{
public static void TestMethod(Person k)
{
k.Name = "Changed";
k = null;
}
public static void TestMethod2(ref Person k)
{
k.Name = "Changed Again!";
k = null;
}
}
答案 5 :(得分:-1)
当您将引用类型参数传递给方法时,这意味着该方法可以直接访问该参数而不是它的副本....
结果是改变了。