C# 我能确保给定字符串的内置哈希始终相同吗?

C# 我能确保给定字符串的内置哈希始终相同吗?,c#,.net,string,hash,C#,.net,String,Hash,我得到的字符串哈希如下: string content = "a very long string"; int contentHash = content.GetHashCode(); 然后,我将散列存储到字典中,作为到另一个ID的键映射。这很有用,因此在默认字典散列计算期间,我不必进行比较,但我可以按键从字典中查找ID 我是否可以确保给定字符串(“非常长的字符串”)的哈希值始终相同 我能确定两个不同的字符串不会有相同的散列吗 另外,如果可能,为不同的字符串获得相同哈希值的可能性有多大?字符串

我得到的字符串哈希如下:

string content = "a very long string";
int contentHash = content.GetHashCode();
然后,我将散列存储到字典中,作为到另一个ID的键映射。这很有用,因此在默认字典散列计算期间,我不必进行比较,但我可以按键从字典中查找ID

我是否可以确保给定字符串(“非常长的字符串”)的哈希值始终相同

我能确定两个不同的字符串不会有相同的散列吗


另外,如果可能,为不同的字符串获得相同哈希值的可能性有多大?

字符串是基于其内容进行哈希的,因此,如果使用默认的GetHashCode,则该哈希值应随时间保持不变。

是的,这是哈希代码的用途!不同版本的运行时tho之间不能保证相同。有关州文件的更多信息

如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值


因此,可以保证给定字符串的哈希代码是相同的。但是,不能保证它是唯一的(可能有其他字符串具有相同的哈希代码)。

是的,它将是一致的,因为字符串是不可变的。然而,我认为你误用了这本字典。您应该让字典通过使用字符串作为键来获取字符串的哈希值。散列不能保证是唯一的,因此您可以用另一个密钥覆盖一个密钥。

如前所述,您可以确保分区字符串的散列与基于内容的散列相同。但是,您不能确定特定字符串的哈希值是否与前面提到的.NET framework的更高版本相同


所以我想说,如果在应用程序内部使用这种方法,那么它是很好的。如果要将值持久化到数据存储中,那么最好滚动您自己的函数,以确保它在不同版本之间保持一致。

正如其他人所指出的,哈希值将随时间保持不变。但为什么要对字符串进行散列,然后将其作为字典的键?哈希不能保证是唯一的。所以你的比较可能是不正确的。让字典来做它的工作。我认为最适合这种情况的集合是。

只是为了补充一些细节,说明更改哈希代码的想法可能来自何处

正如其他答案正确地指出的那样,对于特定的运行时版本,特定字符串的哈希代码总是相同的。无法保证较新的运行时可能出于性能原因而使用不同的算法

String类重写对象中的默认GetHashCode实现

NET中引用类型的默认实现是分配一个顺序ID(由.NET内部持有)并将其分配给对象(对象堆存储有用于存储此哈希代码的插槽,它仅在第一次调用该对象的GetHashCode时分配)

因此,创建一个类的实例,为其分配一些值,然后检索hashcode,然后使用相同的值集执行完全相同的序列,将生成不同的hashcode。这可能就是为什么有些人相信哈希代码可以改变的原因。事实上,虽然它是一个类的实例,该类一旦分配了hashcode,该实例的hashcode就不会改变

编辑:我刚刚注意到,没有一个答案直接涉及到你们每个问题(尽管我认为答案很清楚),只是为了整理一下:-

我是否可以确保给定字符串(“非常长的字符串”)的哈希值始终相同

在你的使用中,是的

我能确定两个不同的字符串不会有相同的散列吗

否。两个不同的字符串可能具有相同的哈希

此外,如果可能,为不同的字符串获取相同哈希值的可能性有多大


概率非常低,从4G域产生的哈希非常随机。

这是一个很好的例子,说明了过早优化的弊端

您是否有探查器或基准测试的输出,告诉您同一哈希桶中的条目之间的字符串比较实际上会导致性能问题

我不这么认为。只需将字符串本身用作字典中的键即可。这就是你应该如何使用它

顺便说一句,不同的字符串远远多于不同的int,所以基本逻辑告诉您,不可能为每个不同的字符串使用不同的hashcode

我可以确定一个 给定字符串(“非常长的字符串”) 会永远不变吗

我能确定两个不同的 字符串不会有相同的散列


您不必猜测运行时或版本,只需使用我在业余时间创建的CaseInsensitiveStringComparer类(您可以将其传递给字典的构造函数,或者如果您使用的是.NET 3.5,一个哈希集):

//
///StringComparer与StringComparer.OrdinalingOreCase基本相同,只是哈希代码函数得到了改进并保证不会更改。
/// 
公共类不区分大小写的StringComparer:StringComparer
{
/// 
///比较两个字符串,忽略大小写
/// 
///第一串
///二线
///比较结果
公共覆盖整型比较(字符串x、字符串y)
{
返回StringComparer.OrdinalIgnoreCase.Compare(x,y);
}
/// 
///检查两个字符串是否相等,忽略大小写
/// 
///第一串
///二线
///如果字符串相等,则为True;如果字符串不相等,则为false
公共覆盖布尔等于(字符串x、字符串y)
{
返回比较(x,y)==0;
}
/// 
///获取字符串的哈希代码,忽略大小写
/// 
///获取哈希代码的字符串
///散列码
公众的
/// <summary>
/// StringComparer that is basically the same as StringComparer.OrdinalIgnoreCase, except that the hash code function is improved and guaranteed not to change.
/// </summary>
public class CaseInsensitiveStringComparer : StringComparer
{
    /// <summary>
    /// Compares two strings, ignoring case
    /// </summary>
    /// <param name="x">First string</param>
    /// <param name="y">Second string</param>
    /// <returns>Compare result</returns>
    public override int Compare(string x, string y)
    {
        return StringComparer.OrdinalIgnoreCase.Compare(x, y);
    }

    /// <summary>
    /// Checks if two strings are equal, ignoring case
    /// </summary>
    /// <param name="x">First string</param>
    /// <param name="y">Second string</param>
    /// <returns>True if strings are equal, false if not</returns>
    public override bool Equals(string x, string y)
    {
        return Compare(x, y) == 0;
    }

    /// <summary>
    /// Gets a hash code for a string, ignoring case
    /// </summary>
    /// <param name="obj">String to get hash code for</param>
    /// <returns>Hash code</returns>
    public override int GetHashCode(string obj)
    {
        if (obj == null)
        {
            return 0;
        }
        int hashCode = 5381;
        char c;
        for (int i = 0; i < obj.Length; i++)
        {
            c = obj[i];
            if (char.IsLower(c))
            {
                c = char.ToUpperInvariant(c);
            }
            hashCode = ((hashCode << 5) + hashCode) + c;
        }
        return hashCode;
    }
}
 The equals method implements an equivalence relation:

* It is reflexive: for any reference value x, x.equals(x) should return true.
* It is symmetric: for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
* It is transitive: for any reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
* It is consistent: for any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the object is modified.
* For any non-null reference value x, x.equals(null) should return false.