C# 为什么字符串对象必须通过引用传递?
在C#中,据我所知,方法调用期间参数的传递是按值进行的。但当您使用对象作为参数时,您传递的是对象本身的引用。这意味着,如果您访问(并修改)对象内某个字段的值,则在方法调用完成后也会看到更新 因此,如果我在方法中修改字符串的值,那么应该在方法调用终止时修改它(因为字符串是C#中的对象)。但事实并非如此,如果我写:C# 为什么字符串对象必须通过引用传递?,c#,pass-by-reference,pass-by-value,C#,Pass By Reference,Pass By Value,在C#中,据我所知,方法调用期间参数的传递是按值进行的。但当您使用对象作为参数时,您传递的是对象本身的引用。这意味着,如果您访问(并修改)对象内某个字段的值,则在方法调用完成后也会看到更新 因此,如果我在方法中修改字符串的值,那么应该在方法调用终止时修改它(因为字符串是C#中的对象)。但事实并非如此,如果我写: public static void main (String []args){ String s= "hello"; method(s); System.Console.W
public static void main (String []args){
String s= "hello";
method(s);
System.Console.Writeline(s);
}
public void method (String s)
{s = "world";}
它将打印“你好”,而不是“世界”。打印“world”的唯一方法是在方法签名和调用中添加关键字ref
为什么会发生这种情况?我的答案(我希望您确认或更正)是,在C#中,字符串对象是不可变的,因此如果我使s=“world”实际上编译器正在创建一个新的字符串对象,但是对对象字符串s的引用不会改变(因为这段是按值进行的)
事实上,如果我在调用method()
之前和之后打印s.getHashCode()
,这两个值是不同的
你觉得我的解释怎么样
因此,如果我在方法中修改字符串的值,那么应该在方法调用终止时修改它(因为字符串是C#中的对象)。但事实并非如此,如果我写:
public static void main (String []args){
String s= "hello";
method(s);
System.Console.Writeline(s);
}
public void method (String s)
{s = "world";}
您没有修改字符串
对象。您正在修改参数以引用不同的字符串。这只是更改一个局部变量,调用者看不到
字符串引用是按值传递的,就像正常情况一样。您需要区分更改参数值和修改参数值引用的对象。您将在自己的类中看到完全相同的行为,即使它是可变的:
class Person
{
public string Name { get; set; }
}
class Test
{
static void Main()
{
var p = new Person { Name = "Tom" };
Method(p);
Console.WriteLine(p.Name);
}
static void Method(Person parameter)
{
parameter = new Person { Name = "Robin" };
}
}
现在,如果在方法中
对对象进行了更改,例如
static void Method(Person parameter)
{
parameter.Name = "Robin";
}
。。。然后您将看到输出的变化。但这并不是在修改参数。字符串的不变性与此相关的唯一原因是,当参数是字符串时,这意味着上面的方法的第二个版本
没有等价物(在安全代码中)
有关更多详细信息,请参阅。它与字符串不变性无关。这是引用类型变量的默认行为。指定新引用时,您正在更改变量的引用值。引用同一位置的其他变量不受该赋值的影响。在您的情况下,当您不使用ref
时,s
的参考值将被复制到参数中,如下所示:
string s = "hello"
string parameter = s;
在此之后,如果您为参数
指定了一个新的引用,它只会更改参数
指向的位置,并且不会影响s
。当您使用ref
时,没有复制。在这种情况下,您实际上传递的是引用,而不是引用的副本。这就是为什么您可以将s
指向的位置更改为。这同样适用于所有引用类型,而不仅仅是字符串
因此,如果我在方法中修改字符串的值,那么应该在方法调用终止时修改它(因为字符串是C#中的对象)
是的,完全正确。如果您能够修改实际的字符串
实例,则调用方将能够观察到该更改
当然,因为string
是不可变的,所以您无法修改string实例。这就是它不可变的含义
由于您没有实际修改字符串
实例,因此调用者没有实际观察的修改
您在代码中所做的不是修改字符串实例,而是修改保存字符串引用的变量。该变量与main方法中的局部变量完全不同。修改一个不会影响另一个(除非使用ref
)
您所拥有的是完全不同的变量,每个变量都引用一个字符串。如果更改这两个引用的字符串,则可以从任意位置观察到该更改。将其中一个变量更改为引用新的变量不是另一个变量可以观察到的。该方法会创建一个指向内存中相同空间的新变量。您正在更改方法中的变量
以指向其他对象,而不是main
中的变量。这涉及字符串的不变性。不是参数传递。所以(只是为了检查我是否理解正确)您告诉我,当我调用该方法时,参数指向作为参数传递给该方法的String对象。但是,当我在方法内部赋值时,参数将指向另一个字符串对象(因为,就像我说的,字符串是不可变的),它的值是“world”,而原来的“hello”字符串根本没有改变,它不再被指向了!我是对的还是我仍然不明白?@MattClark这两个问题都与这个问题有关。@justHelloWorld:我是说main
中s
的值被复制到method
中的s
,因为这就是通过值传递的意思。然后在方法中为s
指定一个新值,这不会改变main
中s
的值,因为这也是“按值传递”的含义。您需要了解s
的值不是一个字符串,而是一个引用。。。剩下的就直截了当了。(假设你有int
值-你不会期望method
中的s=10
更改main
中s
的值,你会吗?)我现在完全理解你的答案,但我仍然认为在某种程度上字符串不变性属性仍然以某种方式存在,事实上:字符串是im