C# .NET字典实现如何处理可变对象
我理解不建议使用“可变”对象(对象的GetHashCode()方法可以返回不同的结果,而它们被用作 以下是我对作为哈希表实现的字典如何工作的理解: 当我添加新键时,例如C# .NET字典实现如何处理可变对象,c#,.net,data-structures,hashtable,C#,.net,Data Structures,Hashtable,我理解不建议使用“可变”对象(对象的GetHashCode()方法可以返回不同的结果,而它们被用作 以下是我对作为哈希表实现的字典如何工作的理解: 当我添加新键时,例如dict.Add(m1,“最初这里是m1对象”),dict使用GetHashCode()方法计算m1的hashcode。然后它进行一些内部计算,最后将该对象放入其内部数组的某个位置 当我使用键索引获取值时,例如dict[m1],dict再次计算hashcode。然后它做了一些内部计算,它给了我一个对象,它位于它内部数组的计算位置
dict.Add(m1,“最初这里是m1对象”)
,dict
使用GetHashCode()
方法计算m1
的hashcode。然后它进行一些内部计算,最后将该对象放入其内部数组的某个位置
当我使用键索引获取值时,例如dict[m1]
,dict
再次计算hashcode。然后它做了一些内部计算,它给了我一个对象,它位于它内部数组的计算位置
但是我认为有一个错误我找不到
假设我有以下代码:
class MutableObject
{
Int32 m_value;
public MutableObject(Int32 value)
{
m_value = value;
}
public void Mutate(Int32 value)
{
m_value = value;
}
public override int GetHashCode()
{
return m_value;
}
}
static void Main(string[] args)
{
MutableObject m1 = new MutableObject(1);
MutableObject m2 = new MutableObject(2);
var dict = new Dictionary<MutableObject, String>();
dict.Add(m1, "initially here was m1 object");
dict.Add(m2, "initially here was m2 object");
Console.WriteLine("Before mutation:");
Console.WriteLine("dict[m1] = " + dict[m1]);
Console.WriteLine("dict[m2] = " + dict[m2]);
m1.Mutate(2);
m2.Mutate(1);
Console.WriteLine("After mutation:");
Console.WriteLine("dict[m1] = " + dict[m1]);
Console.WriteLine("dict[m2] = " + dict[m2]);
Console.ReadKey(true);
}
类可变对象
{
Int32 m_值;
公共可变对象(Int32值)
{
m_值=值;
}
public void Mutate(Int32值)
{
m_值=值;
}
公共覆盖int GetHashCode()
{
返回m_值;
}
}
静态void Main(字符串[]参数)
{
可变对象m1=新的可变对象(1);
可变对象m2=新的可变对象(2);
var dict=新字典();
dict.Add(m1,“最初这里是m1对象”);
dict.Add(m2,“最初这里是m2对象”);
控制台。WriteLine(“突变前:”);
Console.WriteLine(“dict[m1]=”+dict[m1]);
Console.WriteLine(“dict[m2]=”+dict[m2]);
m1.突变(2);
m2.突变(1);
控制台。WriteLine(“突变后:”);
Console.WriteLine(“dict[m1]=”+dict[m1]);
Console.WriteLine(“dict[m2]=”+dict[m2]);
Console.ReadKey(true);
}
当我调用
Mutate
方法时,键被交换。所以我想它会给出交换的结果。但实际上这行:Console.WriteLine(“dict[m1]=”+dict[m1])代码>抛出KeyNotFoundException,我不明白为什么。很明显,我在这里遗漏了一些东西…仅仅进行字典查找来获得相同的哈希代码是不够的。由于散列冲突是可能的,因此该键也必须与正在查找的索引相等。仅进行字典查找以获得相同的散列代码是不够的。由于散列冲突是可能的,因此键也必须与正在查找的索引相等。您的MutableObject
类不会覆盖Equals(object)
。因此使用了引用相等(从基类继承而来的System.Object
)
字典
首先(快速)查找具有正确哈希代码的所有键。然后,它检查每个候选密钥,以检查其中一个是否等于它正在搜索的密钥
因此,Equals(object)
和GetHashCode()
应该一起重写。如果您只覆盖其中一个,则会从编译器收到警告
当密钥在字典
中时,一旦密钥的散列码发生变异,该密钥(可能)就会(可能)被错误地放在字典
中,被放在错误的“bucket”中,并因此丢失。它不会被找到,因为对它的搜索总是在它不在的桶中进行
在本例中,密钥丢失,因此可以再次添加:
var dict = new Dictionary<MutableObject, string>();
var m = new MutableObject(1);
dict.Add(m, "Hello");
m.Mutate(2);
dict.Add(m, "world");
foreach (var p in dict)
Console.WriteLine(p);
var otherDict = new Dictionary<MutableObject, string>(dict); // throws
var dict=newdictionary();
var m=新的可变对象(1);
dict.Add(m,“你好”);
m、 突变(2);
添加(m,“世界”);
foreach(dict中的var p)
控制台写入线(p);
var otherDict=新字典(dict);//投掷
我实际上看到过这样一个异常,在初始化一个字典
时,使用现有字典
中的项(都使用默认的EqualityComparer
作为键类型)。您的可变对象
类不会覆盖Equals(object)
。因此使用了引用相等(从基类继承而来的System.Object
)
字典
首先(快速)查找具有正确哈希代码的所有键。然后,它检查每个候选密钥,以检查其中一个是否等于它正在搜索的密钥
因此,Equals(object)
和GetHashCode()
应该一起重写。如果您只覆盖其中一个,则会从编译器收到警告
当密钥在字典
中时,一旦密钥的散列码发生变异,该密钥(可能)就会(可能)被错误地放在字典
中,被放在错误的“bucket”中,并因此丢失。它不会被找到,因为对它的搜索总是在它不在的桶中进行
在本例中,密钥丢失,因此可以再次添加:
var dict = new Dictionary<MutableObject, string>();
var m = new MutableObject(1);
dict.Add(m, "Hello");
m.Mutate(2);
dict.Add(m, "world");
foreach (var p in dict)
Console.WriteLine(p);
var otherDict = new Dictionary<MutableObject, string>(dict); // throws
var dict=newdictionary();
var m=新的可变对象(1);
dict.Add(m,“你好”);
m、 突变(2);
添加(m,“世界”);
foreach(dict中的var p)
控制台写入线(p);
var otherDict=新字典(dict);//投掷
我实际上看到过这样一个异常,在初始化一个字典
时,使用现有字典
中的项(都使用默认的EqualityComparer
作为键类型)
.NET字典实现如何处理可变对象
没有。各国:
只要对象被用作字典中的键,它就不能以任何影响其哈希值的方式进行更改
由于您正在更改对象,而该对象位于字典中,因此它将不起作用
至于原因,不难看出。我们放入一个物体。让我们假设哈希值是co