如何在CLR中创建和管理字符串?

时间:2012-04-08 17:40:38

标签: c# string clr

我和我的朋友正在讨论Dotnet框架中的字符串,它们是如何引用类型但是就像值类型(不可变)一样。我们都知道字符串是CLR的内部字符串,但我们在那个简短的讨论中并没有真正得出结论,CLR / Framework是如何创建和管理字符串的。

例如,在下面的代码中,s1s2是不同的实例,但正如您所看到的那样s2.ToUpper(),结果请参阅{{1} }。

s1

所以,问题是调用 public static void Main (string[] args) { string s1 = "HELLO"; string s2 = "hello"; Console.WriteLine (s1.GetHashCode()); //Prints 68624562 Console.WriteLine (s2.GetHashCode()); //Prints 99162322 Console.WriteLine (s2.ToUpper().GetHashCode()); //Prints 68624562 too! } CLR是否创建了新的字符串s2.ToUpper()并检查它是否已经存在,如果是,那么扔掉新创建的字符串?有人可以解释这里的魔力吗?

5 个答案:

答案 0 :(得分:3)

String.GetHashCode()生成一个基于字符串的 content 的哈希值。因此,相同的字符串生成相同的哈希是完全自然的。暗示您无法断定ToUpper()返回的字符串引用必须与s1引用匹配。实际上并没有那么昂贵。

您可以通过测试此代码来验证:

    static void Main(string[] args) {
        var s1 = "hello";
        var s2 = "HELLO";
        var s3 = s1.ToUpper();
        bool eq = object.ReferenceEquals(s2, s3);
        System.Diagnostics.Debug.Assert(!eq);
    } 

答案 1 :(得分:3)

对于相同的输入,两个GetHashCode()调用给出相同的结果并不奇怪,这就是哈希点......

相反,当你这样做时:

Console.WriteLine(Object.ReferenceEquals(s2.ToUpper(), s1));

它只返回false。因此,你真的有两个string个实例,两个都有相同的内容。

我认为您需要了解有关散列,哈希码和相等的知识。

或者你来自Java?也许你得到的印象哈希码与对象引用值有关,因为Object.getHashCode()的文档说明了:

  

尽可能合理,Object类定义的hashCode方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要此实现技术。)

答案 2 :(得分:2)

您不能使用GetHashCode()来唯一标识实例。对于具有相同值的两个不同对象,哈希码具有是相同的。否则它将无法作为哈希码。

答案 3 :(得分:1)

s2.ToUpper()只是方法调用,不会改变s2对象的值(s2是String类型的对象)。它获取s2的值并返回具有“HELLO”值的String类的新实例(ToUpper()方法的结果)。 在Main函数的范围内,仍然有两个对象s1和s2,它们的值保持不变。

答案 4 :(得分:0)

要添加,请回答您的其他部分......

如果你也检查了这个Object.ReferenceEquals(s2.ToUpper(), s2),你会发现它也是假的。

字符串是immutable - 在这种情况下意味着ToUpper()返回一个新实例。

所以答案是肯定的,“HELLO”是新的字符串。

然而,正如其他人所说,GetHashCode()只是一个'哈希值' - 它主要用于在处理哈希和词典时使用多种算法来“填充桶”。

或者看到这个链接What is the best algorithm for an overridden System.Object.GetHashCode? - 答案 - 让你很好地理解哈希算法是如何工作的 - 以及为什么它不是唯一的 - 以及为什么它对于具有相同内容的字符串可能是相同的。

或者这一个http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/