来自里希特和这次讨论 https://stackoverflow.com/questions/8482479/why-are-2-separate-string-references-equal-in-other-words-why-are-s-and-t-both,我希望任何两个“相同”字符串都是相同的引用。但刚才在 LINQPad 中,我在这个主题上得到了好坏参半的结果。这是代码:
void Main()
{
string alpha = String.Format("Hello{0}", 5);
string brava = String.Format("Hello{0}", 5);
ReferenceEquals(alpha, brava).Dump();
String.IsInterned(alpha).Dump();
String.IsInterned(brava).Dump();
alpha = "hello";
brava = "hello";
ReferenceEquals(alpha, brava).Dump();
}
以下是 Dump() 调用的结果:
False
Hello5
Hello5
True
我本来期望第一个和最后一个ReferenceEquals
to be True
。发生了什么?
除了上面的示例之外,ReferenceEquals 在其他什么情况下会失败?例如,多线程?
例如,如果我使用传递到方法中的字符串参数作为锁定的对象,那么这个问题就很重要。在这种情况下,参考文献最好是相同的!
动态创建的字符串不会发生字符串驻留。这包括由 String.Format 和 StringBuilder 创建的那些(我相信 String.Format 在内部使用 StringBuilder )。 MSDN 的文档字符串实习生 http://msdn.microsoft.com/en-us/library/system.string.intern.aspx表明这一点:
在以下示例中,字符串 s1 的值为
“MyTest”已经被实习,因为它是程序中的文字。
System.Text.StringBuilder 类生成一个新的字符串对象
与 s1 具有相同的值。对该字符串的引用被分配给
s2。 Intern 方法搜索与以下值具有相同值的字符串
s2。因为存在这样的字符串,所以该方法返回相同的
分配给 s1 的引用。然后将该引用分配给
s3。引用 s1 和 s2 比较不相等,因为它们引用
不同的对象;引用 s1 和 s3 比较相等,因为它们
引用同一个字符串。
string s1 = "MyTest";
string s2 = new StringBuilder().Append("My").Append("Test").ToString();
string s3 = String.Intern(s2);
Console.WriteLine((Object)s2==(Object)s1); //Different references.
Console.WriteLine((Object)s3==(Object)s1); //The same reference.
需要注意的关键一点是,对于 CLR 您生成的字符串string.Format("Hello{0}", 5)
不被视为文字字符串,因此加载程序集时不会发生驻留。琴弦"hello"
另一方面被 CLR 拘留。为了实习这些字符串,您必须使用 String.Intern 显式地执行此操作。
Edit
关于您的锁定问题,理论上您可以使用字符串作为锁定对象,但我认为这是不好的做法。您不知道传递给应用程序的字符串来自哪里,因此不能保证它们是相同的参考。这些字符串可能来自数据库读取调用、使用 StringBuilder、使用 String.Format 或用户输入。在这些情况下,您的锁定无法确保一次只有一个线程位于您的临界区中,因为不能保证发生字符串驻留。
即使你could保证您始终使用实习字符串,您仍然会遇到潜在的危险问题。现在,任何人都可以在应用程序中的任何位置(包括其他 AppDomain)锁定相同的字符串引用。这是个坏消息。
我建议有一个显式声明的锁对象(对象类型)。你将为自己节省一个ton调试线程问题(如果出现)的时间。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)