Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.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
假装.NET字符串是值类型_.net_String_Pass By Reference_Pass By Value - Fatal编程技术网

假装.NET字符串是值类型

假装.NET字符串是值类型,.net,string,pass-by-reference,pass-by-value,.net,String,Pass By Reference,Pass By Value,在.NET中,字符串是不可变的,并且是引用类型变量。这常常让较新的.NET开发人员感到惊讶,因为他们的行为可能会将其误认为值类型对象。然而,除了使用StringBuilder进行长串接(尤其是在循环中)的实践之外,在实践中是否有任何理由需要了解这种区别 通过理解.NET字符串的值引用区别,而不是仅仅假装/误解它们是值类型,可以帮助或避免哪些真实场景?字符串是一种特殊类型。它们是引用类型,但被大多数编码人员用作值类型。通过使其不可变并使用intern池,它优化了内存使用,如果它是纯值类型,那么内存

在.NET中,字符串是不可变的,并且是引用类型变量。这常常让较新的.NET开发人员感到惊讶,因为他们的行为可能会将其误认为值类型对象。然而,除了使用
StringBuilder
进行长串接(尤其是在循环中)的实践之外,在实践中是否有任何理由需要了解这种区别


通过理解.NET字符串的值引用区别,而不是仅仅假装/误解它们是值类型,可以帮助或避免哪些真实场景?

字符串是一种特殊类型。它们是引用类型,但被大多数编码人员用作值类型。通过使其不可变并使用intern池,它优化了内存使用,如果它是纯值类型,那么内存使用将是巨大的

此处有更多阅读资料:


更新:

请参考abel对此帖子的评论。它纠正了我的误导性陈述。

对大多数代码来说真正重要的唯一区别是
null
可以分配给字符串变量。

字符串的设计是有意的,作为程序员,您不必太担心它。在许多情况下,这意味着您可以只分配、移动、复制和更改字符串,而不必考虑如果存在对字符串的另一个引用并将在同一时间更改(对象引用就是如此)可能产生的复杂后果

方法调用中的字符串参数 (编辑:本节稍后添加)
当字符串传递给方法时,它们是通过引用传递的。当它们仅在方法体中读取时,不会发生任何特殊情况。但当它们被更改时,将创建一个副本,并在方法的其余部分使用临时变量。这个过程称为写时复制

令junior感到困扰的是,他们习惯于对象是引用,并且在更改传递的参数的方法中更改对象。要对字符串执行相同的操作,它们需要使用
ref
关键字。这实际上允许更改字符串引用并将其返回给调用函数。如果不更改,则方法体无法更改字符串:

void ChangeBad(string s)      { s = "hello world"; }
void ChangeGood(ref string s) { s = "hello world"; }

// in calling method:
string s1 = "hi";
ChangeBad(s1);       // s1 remains "hi" on return, this is often confusing
ChangeGood(ref s1);  // s1 changes to "hello world" on return
关于StringBuilder 这一区别很重要,但初学者通常不太了解它会更好。当您执行大量字符串“构建”时,使用
StringBuilder
是很好的,但通常情况下,您的应用程序会有更多的麻烦,而
StringBuilder
的性能增益微乎其微。要小心那些告诉您所有字符串操作都应该使用StringBuilder的程序员

作为一个非常粗略的经验法则:StringBuilder有一些创建成本,但附加成本很低。字符串的创建成本很低,但连接成本相对较高。转折点大约是400-500次连接,具体取决于大小:之后,StringBuilder的效率会更高

关于StringBuilder与字符串性能的更多信息 编辑:根据康拉德·鲁道夫的评论,我添加了这个部分

如果前面的经验法则让你感到疑惑,请考虑下面一些更详细的解释:

  • 带有许多小字符串附件的StringBuilder很快就超过了字符串连接(30、50个附件),但在2µs上,即使100%的性能增益通常也可以忽略不计(在某些罕见的情况下是安全的)
  • 带有一些大字符串附件(80个字符或更大的字符串)的StringBuilder仅在数千次迭代(有时是千分之一百次迭代)后才能运行字符串连接,并且差异通常只有几个百分点
  • 混合字符串操作(替换、插入、子字符串、正则表达式等)通常会使使用StringBuilder或字符串连接相等
  • 常量的字符串连接可以由编译器、CLR或JIT进行优化,但对于StringBuilder则不行
  • 代码经常混合连接+StringBuilder.AppendString.FormatToString和其他字符串操作,在这种情况下使用StringBuilder几乎没有任何效果
那么,什么时候才是有效的呢?在附加许多小字符串的情况下,例如,将数据序列化到文件中,以及在“写入”到StringBuilder后不需要更改“写入”数据的情况下。在许多方法需要附加某些内容的情况下,因为StringBuilder是引用类型,字符串在更改时会被复制

关于内接弦 当他们试图做一个参考比较,发现在看似相同的情况下,结果有时是真的,有时是假的时候,问题就出现了——不仅仅是初级程序员。怎么搞的?当编译器将字符串暂存并添加到全局静态暂存字符串池时,两个字符串之间的比较可以指向相同的内存地址。当(reference!)比较两个相等的字符串(一个为interned,一个为not)时,将产生false。在处理字符串时,使用
=
比较或
Equals
,不要玩弄
ReferenceEquals

在字符串上。空 在同一个联盟中,使用
String.Empty
时有时会出现一种奇怪的行为:静态
String.Empty
始终是内部变量,但具有赋值的变量则不是。但是,默认情况下,编译器将分配
String.Empty
并指向相同的内存地址。结果:当与
ReferenceEquals
比较时,可变字符串变量返回true,而您可能希望返回false

// emptiness is treated differently:
string empty1 = String.Empty;
string empty2 = "";
string nonEmpty1 = "something";
string nonEmpty2 = "something";

// yields false (debug) true (release)
bool compareNonEmpty = object.ReferenceEquals(nonEmpty1, nonEmpty2);

// yields true (debug) false (release, depends on .NET version and how it's assigned)
bool compareEmpty = object.ReferenceEquals(empty1, empty2);
深入 你基本上是问那些没有经验的人会遇到什么情况。我想我的观点可以归结为避免使用
object.ReferenceEquals
,因为它在与字符串一起使用时不可信。原因是当字符串在