为什么必须通过引用传递 String 对象?

Why a String object has to be passed by reference?

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

因此,如果我在方法中修改了 String 的值,则应该在方法调用终止时修改它(因为 String 是 C# 中的对象)。但这不是真的,事实上如果我写:

public static void main (String []args){
  String s= "hello";
  method(s);
  System.Console.Writeline(s);
}

public void method (String s)
{s = "world";}

它将打印 "hello",而不是 "world"。打印"world"的唯一方法是在方法签名中添加关键字ref并调用

为什么会这样?我的回答(我希望你确认或更正)是在 C# 中,字符串对象是不可变的,所以如果我让 s="world" 实际上,编译器正在创建一个新的字符串对象,但是对该对象的引用字符串 s 没有改变(因为段落是按值)。

事实上,如果我在 method() 调用之前和之后打印 s.getHashCode(),这两个值是不同的。

你觉得我的解释怎么样?

So, if I modify the value of a String inside a method, it should be modified when the method call is terminated (since String is an object in C#). But this isn't true, in fact if I write:

您没有修改 String 对象。您正在修改 参数 以引用不同的 String。这只是改变了一个局部变量,不是调用者看到的。

正在按值传递字符串引用,就像正常情况一样。您需要区分更改 参数 的值和修改参数值引用的对象。您会看到与您自己的 class 完全相同的行为,即使它是可变的:

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" };
    }
}

现在,如果您在 Method 中更改了 对象 ,例如

static void Method(Person parameter)
{
    parameter.Name = "Robin";
}

... 然后 你会看到输出发生了变化。但这不是修改参数。字符串的不可变性相关的唯一原因是,当参数是字符串时,这意味着上面 Method 的第二个版本没有等效项(在安全代码中)。

有关详细信息,请参阅 my article on parameter passing

它与字符串不变性无关。这是引用类型变量的默认行为。当您分配一个新的引用时,您正在更改变量的引用值。引用同一位置的其他变量不受该分配的影响。在您的情况下,当您不使用 ref 时,s 的参考值将被复制到 parameter 中,如下所示:

string s = "hello"
string parameter = s;

之后,如果您为 parameter 分配新的引用,它只会改变 parameter 指向的位置,不会影响 s。当你使用 ref 时,没有 copying.In 这种情况你 实际上 传递了一个 reference 而不是reference.That 是您可以更改 s 指向的位置的原因。 再次所有引用类型都是如此,而不仅仅是字符串。

So, if I modify the value of a String inside a method, it should be modified when the method call is terminated (since String is an object in C#).

是的,100% 正确。如果您能够修改实际的 string 实例,那么调用者将能够观察到该更改。

当然,因为string 是不可变的所以您无法修改字符串实例。这就是它不可变的意思。

由于您实际上并没有修改 string 实例,因此调用者实际上没有进行任何修改。

您在代码中所做的不是修改字符串实例,而是修改持有字符串引用的变量。该变量与 main 方法中的局部变量完全不同。修改一个不会影响另一个(除非你使用 ref)。

你所拥有的是完全不同的变量,每个变量都有一个字符串的引用。如果您更改两者都引用的字符串,则可以从任一位置观察到该更改。更改任一变量以引用新内容不是另一个变量可以观察到的内容。