Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET字典实现如何处理可变对象_C#_.net_Data Structures_Hashtable - Fatal编程技术网

C# .NET字典实现如何处理可变对象

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。然后它做了一些内部计算,它给了我一个对象,它位于它内部数组的计算位置

我理解不建议使用“可变”对象(对象的GetHashCode()方法可以返回不同的结果,而它们被用作

以下是我对作为哈希表实现的字典如何工作的理解:

当我添加新键时,例如
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
作为键类型)

.NET字典实现如何处理可变对象

没有。各国:

只要对象被用作
字典中的键,它就不能以任何影响其哈希值的方式进行更改

由于您正在更改对象,而该对象位于
字典中,因此它将不起作用

至于原因,不难看出。我们放入一个物体。让我们假设散列代码是
1
。我们将对象放入哈希表的
1
桶中。现在,该对象从字典外部进行变异,使其值(和哈希代码)为
2
。现在,当有人将该对象交给字典的索引器时,它会得到散列码,请看它是
2
,并查看
2
存储桶。那个桶是空的,所以它说,“对不起,没有元素”

现在,我们假设创建了一个新对象,其值和散列为
1
。它被传递给字典,字典看到散列是
1
。它在
1
存储桶中查找,发现该索引中确实存在一个项。它现在使用
Equals
来确定对象是否实际上相等(或者这是否只是散列冲突)

现在,在您的情况下,它将在这里失败,因为您没有覆盖
Equals
,您使用的是比较引用的默认实现,并且由于这是一个不同的对象,因此它将不具有相同的引用。但是,即使您将其更改为比较值,*第一个对象的值发生了变化,变为
2
,而不是
1
,因此它无论如何都不会匹配。其他人建议修复这个
Equals
方法,您确实应该这样做,但它仍然无法解决您的问题

一旦对象发生了变异,找到它的唯一方法就是碰巧变异的值是散列冲突(这是可能的,但不太可能)。如果不是,那么根据
Equals
任何相等的东西都永远不会知道检查正确的b