c# - CLR 字符串引用不(总是)匹配

标签 c# .net .net-4.0

来自 Richter 和 this discussion ,我希望任何两个“相同”的字符串都是相同的引用。但就在 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 都为 True。发生了什么事?

除了上面的例子,在其他什么情况下 ReferenceEquals 会失败?比如多线程?

这个问题很重要,例如,如果我使用传递到方法中的字符串参数作为获取锁的对象。在那种情况下,引用最好是相同的!!!

最佳答案

字符串驻留不会发生在动态创建的字符串上。这包括由 String.Format 和 StringBuilder 创建的那些(我相信 String.Format 在内部使用 StringBuilder)。 MSDN 的 String.Intern 文档表明这一点:

In the following example, the string s1, which has a value of "MyTest", is already interned because it is a literal in the program. The System.Text.StringBuilder class generates a new string object that has the same value as s1. A reference to that string is assigned to s2. The Intern method searches for a string that has the same value as s2. Because such a string exists, the method returns the same reference that is assigned to s1. That reference is then assigned to s3. References s1 and s2 compare unequal because they refer to different objects; references s1 and s3 compare equal because they refer to the same string.

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 明确地这样做。

编辑

关于您的锁定问题,理论上您可以使用字符串作为锁定对象,但我认为这是不好的做法。您不知道传递给应用程序的字符串来自何处,因此不能保证它们是相同的引用。这些字符串可能来自数据库读取调用、使用 StringBuilder、使用 String.Format 或用户输入。在这些情况下,您的锁定不能确保一次只有一个线程在您的临界区中,因为不能保证会发生字符串实习。

即使您可以保证您始终使用内部字符串,您仍然会遇到潜在的危险问题。现在任何人都可以在您的应用程序(包括其他 AppDomain)中的任何地方锁定相同的字符串引用。这是个坏消息。

我建议有一个显式声明的锁对象(对象类型)。如果出现线程问题,您将节省大量时间来调试线程问题。

关于c# - CLR 字符串引用不(总是)匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12829679/

相关文章:

.net - RavenDB:如何使用多映射/减少索引

asp.net - 通过 ASP.NET、Windows 身份验证和模拟,使用智能卡的私钥对数据进行签名

.net - 无法在装有 VS2010/.net4 的电脑上运行基于 .net3.5 的 exe?

c# - 有什么方法可以修改 Visual Studio 模板中的现有文件?

c# - 获取 "-"之前所有字符的正则表达式

.net - 从 Internet 下载 URL 中包含特定日期时间的图像

c# - 将 GUI 程序和控制台应用程序组合成一个 EXE 是个坏主意吗?

c# - "Cannot use fixed local inside lambda expression"

C# Windows 8 Store (Metro, WinRT) 字节数组到 BitmapImage

C# Linq GroupBy,获取每个组中的列列表