【问题标题】:Passing a string as parameter: is it copied or referenced? I'm confused [duplicate]将字符串作为参数传递:它是复制还是引用?我很困惑[重复]
【发布时间】:2020-04-15 04:25:49
【问题描述】:

我一直在阅读有关值和引用类型以及 ref 关键字的内容,特别注意这篇文章:C# string reference type?。 Jon Skeet 的回答“对字符串的引用是按值传递的。按值传递引用和按引用传递对象之间存在很大差异。不幸的是,在这两种情况下都使用了“引用”这个词。即使在他的例子之后也让我感到困惑。

考虑一下:

string x = "foo";

void Bar(string s)
{
    Console.Write(s);
}

Bar(x);

我的问题:当将x 传递给Bar 时,s 是表示内存中x 的完整副本还是s 是指向x 的指针?如果x 真的很大,这将变得相关。当我想要做的只是将s 转换成不同的东西(不改变s 本身?)时,通过ref 传递x 是否会带来性能优势?)

【问题讨论】:

  • 传递的是x的引用副本。顺便说一句,转换 strings 总是会产生新的 strings。
  • 您编写的代码在任何时候都不会创建字符串的多个副本。你不需要通过ref传递它。
  • s 也不是指向x 的指针。 x 是对“foo”的引用。 s 是该引用的副本,指向同一个“foo”。
  • 发送反馈。那么它是否类似于 C 中的**指针?
  • 我会说它类似于*指针。 string 的唯一特别之处在于它是“不可变的”(该类只是不公开任何突变 API)。传递 string 就像传递任何其他 class 对象一样。如果您将Dictionary 传递给函数,则不会期望复制。你基本上是在传递一个指针的副本。

标签: c#


【解决方案1】:

“当将 x 传递给 Bar 时,s 是表示内存中 x 的完整副本还是 s 是指向 x 的指针”。

x 是对“foo”的引用,而不是“foo”的完整副本。

当你这样做时

条形(x)

x 被传递(即传递 x 的副本而不是 x 本身)所以你在 Bar 中所做的任何事情都不会改变 x 所指的内容。如果您希望 Bar 更改 x 所指的内容,则必须使用 ref 关键字通过引用传递它。这需要更改 Bar 的签名,如下所示:

void Bar(ref string s) { }

那么你可以这样称呼它:

条形图(参考 x)

在这种情况下通过引用传递与

无关

性能优势

而是为了实现所期望的(即更改 x 所指的内容)。

【讨论】:

  • 让我困惑的是您的“传递的是 x 的副本而不是 x 本身。”这表明一个副本,而不是其他人“指出”的指针。
  • 传递的是引用的副本(即 x 的副本),而不是“foo”的副本。 x 与“foo”不同,它指向“foo”(我不喜欢在这里使用指针这个词,因为它有来自 C/C++ 的包袱)
【解决方案2】:

当将 x 传递给 Bar 时,s 是否代表 x 的完整副本 在内存中还是 s 是指向 x 的指针?

xs 都是变量,它们引用内存中的同一个 String 对象 - “Foo”。

在以下情况下通过 ref 传递 x 是否会带来性能优势? 我想做的就是将 s 转换成不同的东西(没有 改变 s 本身?)

使用ref 关键字传递s 参数允许您通过将新字符串(或null)分配给s 参数,将x 变量分配给内存中的不同字符串对象(或null) .但是没有性能差异,因为在这两种情况下,只复制了一个地址(分别是字符串“Foo”的地址或变量 x 的地址)——字符串“Foo”的内容不是复制。

【讨论】:

  • 谢谢,正如其他人指出的那样,它指向一个地址,这是我想知道的。
【解决方案3】:

c# 中的所有字符串都是不可变的,因此传递指针是安全的。在您的示例中,“foo”是一个静态常量,将存在于程序集中的某个位置,并被加载到内存中的固定位置。您正在声明 x 并分配该位置。然后将该指针传递给 Bar,其中一个新的局部变量 s 也被分配了该值。

如果 Bar 改变了 s 的值,它不会改变 x 的当前值,因为这两个变量都是指针位置的副本。

如果将 Bar 更改为将 s 作为引用参数,则 s 不再是单独的局部变量。相反,x 本身的位置将被传递给 Bar,并且对 s 和 x 的任何更改都会更改同一个指针。变量 s 成为对指向字符串的变量的引用。

【讨论】:

  • 我从中得到的是,我们在这里谈论的是指针,而不是传递的副本(值),对吧?
  • 类类型总是在堆上分配。类变量总是指针。值类型存储在它们出现的范围内,堆栈上的局部变量,包含它们的类中的类字段。
猜你喜欢
  • 2016-03-10
  • 1970-01-01
  • 2012-05-31
  • 2014-09-28
  • 2016-06-11
  • 1970-01-01
  • 1970-01-01
  • 2013-02-09
  • 2013-05-03
相关资源
最近更新 更多