Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么字符串对象必须通过引用传递?_C#_Pass By Reference_Pass By Value - Fatal编程技术网

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

在C#中,据我所知,方法调用期间参数的传递是按值进行的。但当您使用对象作为参数时,您传递的是对象本身的引用。这意味着,如果您访问(并修改)对象内某个字段的值,则在方法调用完成后也会看到更新

因此,如果我在方法中修改字符串的值,那么应该在方法调用终止时修改它(因为字符串是C#中的对象)。但事实并非如此,如果我写:

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