我听说和读过字符串是不能改变的(不可变的?)。我猜这应该是正确的。但我也听说,两个具有相同内容的字符串共享相同的内存空间(或者你可以称其为什么)。这是正确的吗?
如果是这样,那是否意味着,如果我创建一个包含数千个字符串的列表,如果其中大部分字符串相互相等,那它不会真正占用太多空间吗?
编辑:在下面的答案中,我提到实习池是AppDomain特定的;我很确定这是我以前观察到的,但 String.Intern 的MSDN文档表明整个进程只有一个内部池,使得这一点更加重要。
原始答案
正如其他人所解释的那样,字符串国际化适用于所有字符串文字,但不适用于“动态创建”的字符串(例如从数据库或文件中读取的字符串,或使用StringBuilder
或String.Format
构建的字符串)。
然而,我不建议调用String.Intern
来解决后一个问题:它将填充intern池为您的AppDomain
的生命周期。相反,请使用仅限于您使用的本地池。以下是这样一个池的示例:
public class StringPool
{
private readonly Dictionary<string,string> contents =
new Dictionary<string,string>();
public string Add(string item)
{
string ret;
if (!contents.TryGetValue(item, out ret))
{
contents[item] = item;
ret = item;
}
return ret;
}
}
你可以使用类似以下的代码:
string data = pool.Add(ReadItemFromDatabase());
void ProcessLogFile(string file)
{
StringPool pool = new StringPool();
// Process the log file using strings in the pool
} // The pool can now be garbage collected
在这里,您可以获得同一文件中多个字符串仅存在于内存中一次的好处(或者至少只会经过gen0一次),但是您不会污染“全局”资源(即intern池)。
这基本上是正确的。它被称为“字符串驻留”。字符串文字只会在内存中出现一次,每个设置为相同值的变量都指向此单个表示。在代码中创建的字符串不会自动驻留。
如果我没记错的话,在代码中硬编码的字符串会被单独池化。这称为“Interned”,并且有一种方法可以查询字符串是否:String.IsInterned Method。
在该页面的“备注”下,您可以阅读到:
公共语言运行时会自动维护一个表,称为“intern pool”,其中包含程序中声明的每个唯一文字常量的单个实例,以及您通过编程方式添加的任何唯一 String 实例。
希望这能对你有所帮助,如果我有错误,请指出。
马蒂亚斯
ContainsKey
两次查找然后使用索引器来获取值,当可以通过TryGetValue
一次完成两个操作呢?@C.B.:是的——我需要这个值。 - Jon Skeet