在 C# 中将字符串文字分配给字符串
Posted
技术标签:
【中文标题】在 C# 中将字符串文字分配给字符串【英文标题】:Assigning a string-literal to a string in C# 【发布时间】:2015-09-15 20:44:38 【问题描述】:字符串文字在 C# 中是否具有特定类型(如 C++ 中的 const char*),还是 C# 只是为程序中出现的每个字符串文字创建一个新的字符串对象? 我很想知道执行以下语句时幕后发生了什么:
string s1 = "OldValue";
这会调用字符串类中的特定方法(构造函数,或隐式转换运算符,...)还是 C# 创建一个包含“OldValue”的新字符串对象(然后只需将其引用分配给 s1,就就像任何参考类型一样)?
我试图了解在保证 s1 的值仍然是“OldValue”的字符串类的设计中是什么:
string s2 = s1;
s2 = "NewValue";
【问题讨论】:
***.com/questions/4286614/… 你知道reference types是什么吗? @Sinatr :是的,我知道什么是参考类型。只是想了解:当我写 s2 = "NewValue" 时,是否意味着创建了一个值为 "NewValue" 的字符串对象,然后将对其的引用分配给 s2 ?从下面 quetzalcoatl 的回答来看,似乎是这样 【参考方案1】:最后一个问题,为什么要保留值 - 它不在 String 类中。这是对象引用的工作方式。
String 类不是值类型,它是引用类型。它是一个功能齐全的对象,在“传入/传出变量”时不会被复制。
当你写作时:
string s1 = "mom";
string s2 = s1;
string s3 = s1;
s3 = "dad";
只有一个“妈妈”的实例,它首先在堆中的某个地方创建,然后对它的引用分配给s1。然后创建另一个引用并将其分配给 s2。然后创建另一个引用并将其分配给 s3。没有副本。参考。就像任何真实、正常的 CLR 对象一样。
最后,在最后一行中,在堆上创建了另一个字符串,然后将对其的引用分配给 s3 变量。请注意,这句话完全没有提到“妈妈”或 s1/s2 变量。他们什么都没注意到。
请记住,String 不是值类型。它只是一个普通的不可变对象,有一些方便的 Equals 和 GetHashCode 覆盖。字符串类内部有一些小魔法,但在这里不相关。
【讨论】:
不错的答案,在查找此问题的详细信息时,我发现了一些我不知道的东西。就完全相同值的不同字符串文字而言,CLR 实现了享元模式。重复的字符串字面量实际上分配给同一个引用对象。 @AntonioHaley 这就是所谓的字符串实习。您可以使用string.Intern()
自己调用它
@quetzalcoatl:谢谢!所以关于我的第一个问题: string s1 ="mom" 意味着首先创建一个值为“mom”的字符串对象,然后将 s1 设置为“指向”它......所以字符串文字被视为普通字符串对象(意思是在代码中每次提到字符串文字时,都会创建一个字符串对象来包含它)。
@sam95:你开始明白了。但不,不是那样的。字符串文字是(或可能是)自动实习。这意味着在var s1 = "mom"; var s2 = "mom"; var s3 = "mom"
甚至在完全不同的类var tadam = "mom"
中,编译器会注意到相同的stringliteral 存在4 次,并且将在编译的程序集中创建仅一个 string-literal-entry。稍后在执行时,运行时会注意到使用了 string-from-literal-table 并且将不会创建重复项,但会在引用该字面量条目时重用相同的字符串对象。
@sam95:原因很简单:string
对象被假定和设计为不可变的。因此,没有真正的理由不实习在代码中硬编码的字符串。由于它们是直接用代码编写的,它们将在某个时间点被使用并且它们总是相同的,因为它们是“代码”,所以你希望它们快速。在运行时从用户/文件/网络/等数据创建的其他字符串可能会更大并且它们的内容非常谨慎,因此它们不会自动实习。它会给实习生池发送太多垃圾邮件,所以要小心string.Intern()
方法。【参考方案2】:
好问题。
实际上,在 C# 中,字符串以缓冲区数组的格式存储,其中在每个字符串声明中需要 20 个字节来存储数据并为每个字符发布 2 个字节。 因此,每当您声明任何字符串时,例如字符串 s1 = 'Bhushan'; 然后将创建字符串缓冲区,并具有如下内存要求,
数据所需的字节数(开销):20 字节 每个字符 2 个字节,因此 (2 * 7) : 14 字节 总体而言,它将需要 20 + 14 = 34 字节。
【讨论】:
【参考方案3】:string 是一个不可变的类,这意味着每次我们改变它的值,它都会创建一个新的实例。
string s2 = s1;
s2 = "NewValue";
可以这样解释。
string s2 = s1;
s2 = new string("NewValue"); // It doesn't compile, just an example.
而对于字符串的修改,可以这样解释。
string s = "blah";
s.Insert(0, "blah"); // s is a new instance
同理:
string s = "blah";
s = new string("blah") + new string("blah"); // Doesn't compile, just an explanation
【讨论】:
以上是关于在 C# 中将字符串文字分配给字符串的主要内容,如果未能解决你的问题,请参考以下文章
在从 AppWidgetProvider 调用的异步任务中将字符串分配给文本值