當涉及到盒裝型別時,我對字典如何比較鍵有些困惑。
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int i = 5;
int n = 5;
object boxedI = i;
object boxedN = n;
Console.WriteLine("i == n ? " (i == n) ); //true
Console.WriteLine("bI == bN ? " (boxedI == boxedN) ); //false
Dictionary<object,int> _dict = new Dictionary<object,int> ();
_dict.Add(boxedI,5);
Console.WriteLine("_dict contains boxedI? " _dict.ContainsKey(boxedI) ); //true
Console.WriteLine("_dict contains boxedN? " _dict.ContainsKey(boxedN) ); //!! also true, surprise me
_dict.Add(boxedN,5);//exception
}
}
我預計,由于相等運算子“失敗”(AFAIK,它基于方法 GetHashCode,使用相同的方法字典來構建它的內部哈希表表單物件),那么字典也應該“失敗”盒裝 I 和 N 的比較,但事實并非如此.
這是我使用的小提琴:https : //dotnetfiddle.net/DW54nN
所以我問是否有人可以向我解釋這里追加的內容以及我的心智模型中缺少的內容。
uj5u.com熱心網友回復:
TLDR:==使用裝箱物件的參考相等性比較裝箱值,但Equals()使用基礎值比較裝箱值' Equals()。
當值型別被裝箱時,裝箱物件的GetHashCode()和Equals()方法實作呼叫裝箱值的版本。
也就是說,給定:
- 值型別
VT實作GetHashCode()和Equals()正確。 - 實體
x的VT。 - 實體
y的VT具有相同的值x。 - 的盒裝實體
x:bx。 - 的盒裝實體
y:by。
情況如下:
x.Equals(y) == true // Original values are equal
bx.Equals(by) == true // Boxed values are equal
x.GetHashCode() == y.GetHashCode() // Original hashes are equal
bx.GetHashCode() == by.GetHashCode() // Boxed hashes are equal
bx.GetHashCode() == x.GetHashCode() // Original hash code == boxed hash code
但是,==運算子不是由盒裝版本委托的,實際上它是使用參考相等來實作的,因此:
(x == y) == true // Original values are equal using "=="
(bx == by) == false // Boxed values are not equal using "=="
ReferenceEquals(bx, by) == false // References differ
Dictionary 正在使用GetHashCode()和Equals()用于比較物件,并且因為它們委托給基礎值,所以它可以正常作業。
下面的程式演示了這一點:
using System;
namespace Demo
{
struct MyStruct: IEquatable<MyStruct>
{
public int X;
public bool Equals(MyStruct other)
{
return X == other.X;
}
public override bool Equals(object obj)
{
if (obj is not MyStruct other)
return false;
return X == other.X;
}
public override int GetHashCode()
{
return -X;
}
}
class Program
{
static void Main()
{
var x = new MyStruct { X = 42 };
var y = new MyStruct { X = 42 };
object bx = x;
object by = y;
Console.WriteLine(bx.GetHashCode()); // -42
Console.WriteLine(y.GetHashCode()); // -42
Console.WriteLine(bx.Equals(by)); // True
Console.WriteLine(bx == by); // False
Console.WriteLine(object.ReferenceEquals(bx, by)); // False
}
}
}
uj5u.com熱心網友回復:
這是一個參考與值型別的東西:
int i = 5;
int n = 5;
這些是值型別并放在堆疊上,因此當我們比較它們時,我們進入堆疊并可以說 i 和 n 的值是 5,這使它們“相等”。
object boxedI = i;
object boxedN = n;
當您將這些值放入object一個“參考”型別時,這意味著將一個值放入堆中,并將一個參考放入堆疊中,因此您可以想象在堆疊中您擁有:
#0005 -> boxedI
#0006 -> boxedN
現在,當你做相等時,你正在比較#0005 == #0006哪些不一樣
但是當您傳遞boxedI或boxedN進入ContainsKey該方法時,知道如何遵循指向堆上值的參考(或指標)(5)。
所以當你要求ContainsKey(boxedI)你正在做的事情是要求ContainsKey(5)(粗略地說)
這就是為什么這兩個是“平等的”
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/365725.html
下一篇:將一本字典轉換為字典串列
