【问题标题】:Is it because of string pooling by CLR or by the GetHashCode() method?是因为 CLR 或 GetHashCode() 方法的字符串池?
【发布时间】:2009-03-31 19:20:26
【问题描述】:

是因为 CLR 的字符串池化还是两个字符串的 GetHashCode() 方法返回相同的值?

string s1 = "xyz";
string s2 = "xyz";
Console.WriteLine(" s1 reference equals s2 : {0}", object.ReferenceEquals(s1, s2));

控制台写道:“s1 引用等于 s2 : True”

我相信,这不是因为 GetHashCode() 为两个字符串实例返回相同的值。因为,我使用自定义对象进行了测试,并重写了 GetHasCode() 方法以每次都返回一个常量。此对象的两个单独实例在引用中不相等。

请告诉我,幕后发生了什么。

谢谢 123开发人员

【问题讨论】:

    标签: c# string


    【解决方案1】:

    听起来像string interning - 一种只存储一个字符串副本的方法。它要求字符串是您正在处理的语言中的不可变类型,而 .Net 满足这一要求并使用字符串实习。

    在字符串实习中,字符串“xyz”存储在实习池中,每当您在内部说“xyz”时,它都会引用池中的条目。这可以通过只存储一次字符串来节省空间。因此,“xyz”==“xyz”的比较将被解释为 [pointer to 34576] == [pointer to 34576] 这是真的。

    【讨论】:

    • +1 也许在你的回答中引用这篇文章会有所帮助。
    【解决方案2】:

    这肯定是由于字符串实习。在将引用与object.ReferenceEquals 进行比较时,从不计算哈希码。

    来自 C# 规范,第 2.4.4.5 节:

    每个字符串文字不 必然导致一个新的字符串 实例。当两个或多个字符串 根据等价的文字 到字符串相等运算符 (§7.9.7) 出现在同一个程序中, 这些字符串文字指的是 相同的字符串实例。

    注意字符串常量表达式在这种情况下算作文字,所以:

    string x = "a" + "b";
    string y = "ab";
    

    保证xy 也引用相同的对象(即它们是相同的引用)。

    顺便说一句,当规范说“程序”时,它的真正意思是“组装”。不同程序集中相同字符串的行为取决于 CompilationRelaxations.NoStringInterning 以及精确的 CLR 实现和执行时间情况(例如,程序集是否为 ngen'd)。

    【讨论】:

    • @Jon 字符串 x = "a" + "b";只不过是字符串 x = "ab";它会在编译时发生,对吧?我们可以说前一种语法的存在只是为了提高可读性吗?
    • @123Developer:这不仅仅是可读性——“a”实际上可能是 SomeClass.StringConstant ,在源代码中复制会很糟糕。但是,是的,它们是完全等价的。连接是在编译时执行的。
    【解决方案3】:

    它类似于字符串池,但它不是在运行时完成,而是在编译时完成。

    程序集中的任何字符串文字只存在一次。编译器对字符串文字“xyz”的所有出现使用相同的常量字符串。由于字符串是不可变的(您永远无法更改字符串实例的值),因此编译器可以安全地使用相同的字符串实例来进行单独的字符串引用。

    如果你改为在运行时创建一个字符串,你会得到一个单独的实例:

    string s1 = "xyz";
    
    string s2 = "xy";
    s2 += "z";
    
    Console.WriteLine("s1 ref = s2 : {0}", object.ReferenceEquals(s1, s2));
    

    输出:

    s1 ref = s2 : False
    

    【讨论】:

      【解决方案4】:

      完全同意Tom's answer...

      摘自CIL Specification(第 126 页)

      CLI 保证 两个 ldstr 指令指的是 具有相同的两个元数据令牌 字符序列,返回 完全相同的字符串对象(一个 过程称为“字符串实习”)。

      【讨论】:

        【解决方案5】:

        字符串实习与它无关。

        如果发现 .NET/C# 编译器隐式调用 Intern,我会感到非常惊讶,在运行时检查匹配字符串对 CPU 的压力太大。

        【讨论】:

        • 你错了。运算符不是虚拟的。 object.ReferenceEquals 方法不会调用 operator==(string,string) 而是 operator==(object,object)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-20
        • 2021-01-20
        • 2013-01-07
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        • 2018-02-09
        相关资源
        最近更新 更多