gpt4 book ai didi

.net - .NET 中的字符串是如何传递的?

转载 作者:行者123 更新时间:2023-12-02 13:00:50 25 4
gpt4 key购买 nike

当我通过 string指向函数,是指向传递的字符串内容的指针,或者是整个字符串传递给堆栈上的函数,如 struct会吗?

最佳答案

传递了一个引用;然而,它在技术上并不是通过引用传递的。这是一个微妙但非常重要的区别。考虑以下代码:

void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
要了解此处发生的情况,您需要了解三件事:
  • 字符串是 C# 中的引用类型。
  • 它们也是不可变的,所以每当你做一些看起来像是在改变字符串的事情时,你就不是。一个全新的字符串被创建,引用指向它,旧的被丢弃。
  • 即使字符串是引用类型,strMain不是通过引用传递的。这是一个 引用类型,但引用本身是 按值传递 .任何时候你传递一个没有 ref 的参数关键字(不计算 out 参数),您已经按值传递了一些东西。

  • 所以这一定意味着你正在......通过值传递引用。因为它是一个引用类型,所以只有引用被复制到堆栈上。但这意味着什么?
    按值传递引用类型:您已经在做
    C# 变量是 引用类型 值类型 . C# 参数是 通过引用 按值传递 .术语在这里是个问题。这些听起来像是同一件事,但它们不是。
    如果您传递任何类型的参数,并且不使用 ref关键字,那么您已经按值传递了它。如果您按值传递了它,那么您真正传递的是一个副本。但是如果参数是引用类型,那么你复制的就是 引用,不是它所指的任何东西。
    这是 Main 的第一行方法:
    string strMain = "main";
    我们在这一行创建了两个东西:一个值为 main 的字符串。存储在内存中的某处,以及一个名为 strMain 的引用变量指向它。
    DoSomething(strMain);
    现在我们将该引用传递给 DoSomething .我们已经按值传递了它,所以这意味着我们制作了一个副本。它是一个引用类型,所以这意味着我们复制了引用,而不是字符串本身。现在我们有两个引用,每个引用都指向内存中的相同值。
    被调用者内部
    这是 DoSomething的顶部方法:
    void DoSomething(string strLocal)
    ref关键字,所以 strLocalstrMain是指向相同值的两个不同引用。如果我们重新分配 strLocal ...
    strLocal = "local";   
    ...我们没有改变存储的值;我们采用了名为 strLocal 的引用文献并瞄准了一个全新的字符串。 strMain会发生什么|当我们这样做时? Nothing. It's still pointing at the old string.
    string strMain = "main";    // Store a string, create a reference to it
    DoSomething(strMain); // Reference gets copied, copy gets re-pointed
    Console.WriteLine(strMain); // The original string is still "main"
    不变性
    让我们改变一下场景。想象一下,我们处理的不是字符串,而是一些可变引用类型,比如您创建的类。
    class MutableThing
    {
    public int ChangeMe { get; set; }
    }
    如果您按照引用 objLocal对于它指向的对象,您可以更改其属性:
    void DoSomething(MutableThing objLocal)
    {
    objLocal.ChangeMe = 0;
    }
    仍然只有一个 MutableThing在内存中,复制的引用和原始引用仍然指向它。 The properties of the MutableThing itself have changed :
    void Main()
    {
    var objMain = new MutableThing();
    objMain.ChangeMe = 5;
    Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain

    DoSomething(objMain); // now it's 0 on objLocal
    Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain
    }
    啊,但是字符串是不可变的!没有 ChangeMe要设置的属性。你做不到 strLocal[3] = 'H'在 C# 中就像使用 C 风格一样 char数组;你必须构造一个全新的字符串。改变的唯一途径 strLocal是将引用指向另一个字符串,这意味着您无需对 strLocal 做任何事情可能会影响 strMain .值是不可变的,引用是副本。
    通过引用传递引用
    为了证明存在差异,这里是发生了什么 when you pass a reference by reference:
    void DoSomethingByReference(ref string strLocal)
    {
    strLocal = "local";
    }
    void Main()
    {
    string strMain = "main";
    DoSomethingByReference(ref strMain);
    Console.WriteLine(strMain); // Prints "local"
    }
    这次是 Main中的字符串确实会发生变化,因为您传递了引用而不将其复制到堆栈中。
    因此,即使字符串是引用类型,通过值传递它们也意味着被调用者中发生的任何事情都不会影响调用者中的字符串。但是因为它们是引用类型,所以当你想要传递它时,你不必在内存中复制整个字符串。
    更多资源:
  • 这是我在 the difference between reference types and value types in C# 上读过的最好的文章,以及为什么引用类型与引用传递的参数不同。
  • 和往常一样,Eric Lippert 也有 several excellent blog posts on the subject .
  • 他有 some great stuff on immutability ,也是。
  • 关于.net - .NET 中的字符串是如何传递的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10792603/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com