Object.GetHashCode Metode
Definisi
Penting
Beberapa informasi terkait produk prarilis yang dapat diubah secara signifikan sebelum dirilis. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Berfungsi sebagai fungsi hash default.
public:
virtual int GetHashCode();
public virtual int GetHashCode();
abstract member GetHashCode : unit -> int
override this.GetHashCode : unit -> int
Public Overridable Function GetHashCode () As Integer
Mengembalikan
Kode hash untuk objek saat ini.
Contoh
Salah satu cara paling sederhana untuk menghitung kode hash untuk nilai numerik yang memiliki rentang yang sama atau lebih kecil daripada tipe Int32 adalah dengan cukup mengembalikan nilai tersebut. Contoh berikut menunjukkan implementasi seperti itu untuk Number struktur.
using System;
public struct Number
{
private int n;
public Number(int value)
{
n = value;
}
public int Value
{
get { return n; }
}
public override bool Equals(Object obj)
{
if (obj == null || ! (obj is Number))
return false;
else
return n == ((Number) obj).n;
}
public override int GetHashCode()
{
return n;
}
public override string ToString()
{
return n.ToString();
}
}
public class Example1
{
public static void Main()
{
Random rnd = new Random();
for (int ctr = 0; ctr <= 9; ctr++) {
int randomN = rnd.Next(Int32.MinValue, Int32.MaxValue);
Number n = new Number(randomN);
Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode());
}
}
}
// The example displays output like the following:
// n = -634398368, hash code = -634398368
// n = 2136747730, hash code = 2136747730
// n = -1973417279, hash code = -1973417279
// n = 1101478715, hash code = 1101478715
// n = 2078057429, hash code = 2078057429
// n = -334489950, hash code = -334489950
// n = -68958230, hash code = -68958230
// n = -379951485, hash code = -379951485
// n = -31553685, hash code = -31553685
// n = 2105429592, hash code = 2105429592
open System
[<Struct; CustomEquality; NoComparison>]
type Number(value: int) =
member _.Value = value
override _.Equals(obj) =
match obj with
| :? Number as n ->
n.Value = value
| _ -> false
override _.GetHashCode() =
value
override _.ToString() =
string value
let rnd = Random()
for _ = 0 to 9 do
let randomN = rnd.Next(Int32.MinValue, Int32.MaxValue)
let n = Number randomN
printfn $"n = {n,12}, hash code = {n.GetHashCode(),12}"
// The example displays output like the following:
// n = -634398368, hash code = -634398368
// n = 2136747730, hash code = 2136747730
// n = -1973417279, hash code = -1973417279
// n = 1101478715, hash code = 1101478715
// n = 2078057429, hash code = 2078057429
// n = -334489950, hash code = -334489950
// n = -68958230, hash code = -68958230
// n = -379951485, hash code = -379951485
// n = -31553685, hash code = -31553685
// n = 2105429592, hash code = 2105429592
Public Structure Number
Private n As Integer
Public Sub New(value As Integer)
n = value
End Sub
Public ReadOnly Property Value As Integer
Get
Return n
End Get
End Property
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing OrElse Not TypeOf obj Is Number Then
Return False
Else
Return n = CType(obj, Number).n
End If
End Function
Public Overrides Function GetHashCode() As Integer
Return n
End Function
Public Overrides Function ToString() As String
Return n.ToString()
End Function
End Structure
Module Example1
Public Sub Main()
Dim rnd As New Random()
For ctr As Integer = 0 To 9
Dim randomN As Integer = rnd.Next(Int32.MinValue, Int32.MaxValue)
Dim n As New Number(randomN)
Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode())
Next
End Sub
End Module
' The example displays output like the following:
' n = -634398368, hash code = -634398368
' n = 2136747730, hash code = 2136747730
' n = -1973417279, hash code = -1973417279
' n = 1101478715, hash code = 1101478715
' n = 2078057429, hash code = 2078057429
' n = -334489950, hash code = -334489950
' n = -68958230, hash code = -68958230
' n = -379951485, hash code = -379951485
' n = -31553685, hash code = -31553685
' n = 2105429592, hash code = 2105429592
Seringkali, tipe memiliki beberapa bidang data yang dapat berpartisipasi dalam menghasilkan kode hash. Salah satu cara untuk menghasilkan kode hash adalah dengan menggabungkan bidang ini menggunakan operasi XOR (eXclusive OR), seperti yang ditunjukkan di contoh berikut.
using System;
// A type that represents a 2-D point.
public struct Point2
{
private int x;
private int y;
public Point2(int x, int y)
{
this.x = x;
this.y = y;
}
public override bool Equals(Object obj)
{
if (! (obj is Point2)) return false;
Point2 p = (Point2) obj;
return x == p.x & y == p.y;
}
public override int GetHashCode()
{
return x ^ y;
}
}
public class Example3
{
public static void Main()
{
Point2 pt = new Point2(5, 8);
Console.WriteLine(pt.GetHashCode());
pt = new Point2(8, 5);
Console.WriteLine(pt.GetHashCode());
}
}
// The example displays the following output:
// 13
// 13
// A type that represents a 2-D point.
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
member _.X = x
member _.Y = y
override _.Equals(obj) =
match obj with
| :? Point as p ->
x = p.X && y = p.Y
| _ ->
false
override _.GetHashCode() =
x ^^^ y
let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"
let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays the following output:
// 13
// 13
' A type that represents a 2-D point.
Public Structure Point3
Private x As Integer
Private y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not TypeOf obj Is Point3 Then Return False
Dim p As Point3 = CType(obj, Point3)
Return x = p.x And y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return x Xor y
End Function
End Structure
Public Module Example3
Public Sub Main()
Dim pt As New Point3(5, 8)
Console.WriteLine(pt.GetHashCode())
pt = New Point3(8, 5)
Console.WriteLine(pt.GetHashCode())
End Sub
End Module
Contoh sebelumnya mengembalikan kode hash yang sama untuk (n1, n2) dan (n2, n1), sehingga mungkin menghasilkan lebih banyak tabrakan daripada yang diinginkan. Pada .NET 5+, solusi yang direkomendasikan adalah menggunakan HashCode.Combine. Ini menghindari masalah simetri dan menghasilkan kode hash yang terdistribusi dengan baik tanpa adanya overhead pembuatan objek Tuple.
using System;
public struct Point3
{
private int x;
private int y;
public Point3(int x, int y)
{
this.x = x;
this.y = y;
}
public override bool Equals(Object obj)
{
if (obj is Point3)
{
Point3 p = (Point3) obj;
return x == p.x & y == p.y;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return HashCode.Combine(x, y);
}
}
public class Example
{
public static void Main()
{
Point3 pt = new Point3(5, 8);
Console.WriteLine(pt.GetHashCode());
pt = new Point3(8, 5);
Console.WriteLine(pt.GetHashCode());
}
}
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
// 185727722
// -363254492
[<Struct; CustomEquality; NoComparison>]
type Point(x: int, y: int) =
member _.X = x
member _.Y = y
override _.Equals(obj) =
match obj with
| :? Point as p ->
x = p.X && y = p.Y
| _ ->
false
override _.GetHashCode() =
System.HashCode.Combine(x, y)
let pt = Point(5, 8)
printfn $"{pt.GetHashCode()}"
let pt2 = Point(8, 5)
printfn $"{pt2.GetHashCode()}"
// The example displays output similar to the following.
// Note: HashCode.Combine results are not stable across .NET versions.
// 185727722
// -363254492
Public Structure Point
Private x As Integer
Private y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
If Not TypeOf obj Is Point Then Return False
Dim p As Point = CType(obj, Point)
Return x = p.x And y = p.y
End Function
Public Overrides Function GetHashCode() As Integer
Return HashCode.Combine(x, y)
End Function
End Structure
Public Module Example
Public Sub Main()
Dim pt As New Point(5, 8)
Console.WriteLine(pt.GetHashCode())
pt = New Point(8, 5)
Console.WriteLine(pt.GetHashCode())
End Sub
End Module
' The example displays output similar to the following.
' Note: HashCode.Combine results are not stable across .NET versions.
' 185727722
' -363254492
Keterangan
Metode ini GetHashCode menyediakan kode hash untuk algoritma yang membutuhkan pemeriksaan cepat kesetaraan objek. Kode hash adalah nilai numerik yang digunakan untuk menyisipkan dan mengidentifikasi objek dalam koleksi berbasis hash, seperti Dictionary<TKey,TValue> kelas, Hashtable kelas, atau jenis yang berasal dari DictionaryBase kelas.
Note
Untuk informasi tentang bagaimana kode hash digunakan dalam tabel hash dan untuk beberapa algoritma kode hash tambahan, lihat entri Fungsi Hash di Wikipedia.
Dua objek yang sama mengembalikan kode hash yang sama. Namun, kebalikannya tidak benar: kode hash yang sama tidak menyiratkan kesetaraan objek, karena objek yang berbeda (tidak sama) dapat memiliki kode hash yang identik. Selain itu, .NET tidak menjamin implementasi default metode GetHashCode, dan nilai yang dikembalikan metode ini mungkin berbeda antara implementasi dan platform .NET, seperti antara platform 32-bit dan 64-bit. Untuk alasan ini, jangan gunakan implementasi default metode ini sebagai pengidentifikasi objek unik untuk tujuan hashing. Dua konsekuensi mengikuti dari ini:
- Anda tidak boleh berasumsi bahwa kode hash yang sama menyiratkan kesetaraan objek.
- Anda tidak boleh bertahan atau menggunakan kode hash di luar domain aplikasi tempat kode dibuat, karena objek yang sama dapat melakukan hash di seluruh domain, proses, dan platform aplikasi.
Warning
Kode hash ditujukan untuk penyisipan dan pencarian yang efisien dalam koleksi yang didasarkan pada tabel hash. Kode hash bukan nilai permanen. Untuk alasan ini:
- Jangan membuat serialisasi nilai kode hash atau menyimpannya dalam database.
- Jangan gunakan kode hash sebagai kunci untuk mengambil objek dari koleksi bertanda kunci.
- Jangan mengirim kode hash di seluruh domain atau proses aplikasi. Dalam beberapa kasus, kode hash dapat dihitung berdasarkan domain per proses atau per aplikasi.
- Jangan gunakan kode hash alih-alih nilai yang dikembalikan oleh fungsi hashing kriptografi jika Anda memerlukan hash yang kuat secara kriptografis. Untuk hash kriptografi, gunakan kelas turunan dari System.Security.Cryptography.HashAlgorithm atau System.Security.Cryptography.KeyedHashAlgorithm.
- Jangan menguji kesetaraan kode hash untuk menentukan apakah dua objek sama. (Objek yang tidak sama dapat memiliki kode hash yang identik.) Untuk menguji kesetaraan, panggil ReferenceEquals metode atau Equals .
Metode GetHashCode ini dapat di-override oleh tipe turunan. Jika GetHashCode tidak ditimpa, kode hash untuk jenis referensi dihitung dengan memanggil metode kelas dasar Object.GetHashCode, yang menghitung kode hash berdasarkan referensi objek; untuk informasi selengkapnya, lihat RuntimeHelpers.GetHashCode. Dengan kata lain, dua objek yang oleh metode ReferenceEquals mengembalikan true memiliki kode hash yang identik. Jika tipe nilai tidak mengganti GetHashCode, metode ValueType.GetHashCode dari kelas dasar menggunakan refleksi untuk menghitung kode hash berdasarkan nilai dari bidang-bidang tipe tersebut. Dengan kata lain, jenis nilai yang bidangnya memiliki nilai yang sama memiliki kode hash yang sama. Untuk informasi selengkapnya tentang penimpaan GetHashCode, lihat bagian "Catatan untuk Pewaris".
Warning
Jika Anda mengganti metode GetHashCode, Anda juga harus mengganti Equals, dan sebaliknya. Jika metode Equals yang menggantikan mengembalikan true saat dua objek diuji untuk kesetaraan, metode GetHashCode yang menggantikan harus mengembalikan nilai yang sama untuk kedua objek.
Jika objek yang digunakan sebagai kunci dalam tabel hash tidak memberikan implementasi yang berguna dari GetHashCode, Anda dapat menetapkan penyedia kode hash dengan implementasi IEqualityComparer ke salah satu overload konstruktor kelas Hashtable.
Catatan Bagi Inheritor
Fungsi hash digunakan untuk menghasilkan angka (kode hash) dengan cepat yang sesuai dengan nilai objek. Fungsi hash biasanya khusus untuk setiap jenis dan, untuk keunikan, harus menggunakan setidaknya salah satu bidang instans sebagai input. Kode hash tidak boleh dihitung dengan menggunakan nilai bidang statis.
Untuk kelas yang berasal dari Object, GetHashCode metode dapat mendelegasikan ke implementasi kelas GetHashCode() dasar hanya jika kelas turunan mendefinisikan kesetaraan menjadi kesetaraan referensi. Implementasi GetHashCode() default untuk jenis referensi mengembalikan kode hash yang setara dengan yang dikembalikan oleh GetHashCode(Object) metode . Anda dapat mengambil alih GetHashCode() jenis referensi yang tidak dapat diubah. Secara umum, untuk jenis referensi yang dapat diubah, Anda harus mengambil alih GetHashCode() hanya jika:
Anda dapat menghitung kode hash dari bidang yang tidak dapat diubah; Atau
Anda dapat memastikan bahwa kode hash objek yang dapat diubah tidak berubah saat objek terkandung dalam koleksi yang bergantung pada kode hashnya.
Jika tidak, Anda mungkin berpikir bahwa objek yang dapat diubah hilang dalam tabel hash. Jika Anda memilih untuk mengambil alih GetHashCode() jenis referensi yang dapat diubah, dokumentasi Anda harus memperjelas bahwa pengguna jenis Anda tidak boleh mengubah nilai objek saat objek disimpan dalam tabel hash.
Untuk jenis nilai, GetHashCode() menyediakan implementasi kode hash default yang menggunakan pantulan. Anda harus mempertimbangkan untuk mengambil alihnya untuk performa yang lebih baik.
Untuk informasi selengkapnya dan contoh bahwa menghitung kode hash dengan berbagai cara, lihat bagian Contoh.
Fungsi hash harus memiliki properti berikut:
Jika dua objek dibandingkan sama, GetHashCode() metode untuk setiap objek harus mengembalikan nilai yang sama. Namun, jika dua objek tidak dibandingkan sebagai sama, GetHashCode() metode untuk dua objek tidak harus mengembalikan nilai yang berbeda.
Metode GetHashCode() untuk objek harus secara konsisten mengembalikan kode hash yang sama selama tidak ada modifikasi pada status objek yang menentukan nilai pengembalian metode System.Object.Equals objek. Perhatikan bahwa ini hanya berlaku untuk eksekusi aplikasi saat ini, dan bahwa kode hash yang berbeda dapat dikembalikan jika aplikasi dijalankan lagi.
Untuk performa terbaik, fungsi hash harus menghasilkan distribusi yang merata untuk semua input, termasuk input yang sangat terkluster. Implikasinya adalah bahwa modifikasi kecil pada status objek harus menghasilkan modifikasi besar pada kode hash yang dihasilkan untuk performa tabel hash terbaik.
Fungsi hash harus murah untuk komputasi.
Metode GetHashCode() ini tidak boleh melemparkan pengecualian.
Misalnya, implementasi GetHashCode() metode yang disediakan oleh String kelas mengembalikan kode hash yang identik untuk nilai string yang identik. Oleh karena itu, dua String objek mengembalikan kode hash yang sama jika mewakili nilai string yang sama. Selain itu, metode ini menggunakan semua karakter dalam string untuk menghasilkan output yang didistribusikan secara acak secara wajar, bahkan ketika input diklusterkan dalam rentang tertentu (misalnya, banyak pengguna mungkin memiliki string yang hanya berisi 128 karakter ASCII yang lebih rendah, meskipun string dapat berisi salah satu dari 65.535 karakter Unicode).
Menyediakan fungsi hash yang baik pada kelas dapat secara signifikan memengaruhi performa penambahan objek tersebut ke tabel hash. Dalam tabel hash dengan kunci yang menyediakan implementasi fungsi hash yang baik, mencari elemen membutuhkan waktu konstan (misalnya, operasi O(1). Dalam tabel hash dengan implementasi fungsi hash yang buruk, performa pencarian tergantung pada jumlah item dalam tabel hash (misalnya, operasi O(n), di mana n adalah jumlah item dalam tabel hash). Pengguna berbahaya dapat memasukkan data yang meningkatkan jumlah tabrakan, yang dapat secara signifikan menurunkan performa aplikasi yang bergantung pada tabel hash, dalam kondisi berikut:
Ketika fungsi hash menghasilkan tabrakan yang sering.
Ketika proporsi besar objek dalam tabel hash menghasilkan kode hash yang sama atau kira-kira sama dengan satu sama lain.
Saat pengguna memasukkan data tempat kode hash dihitung.
Kelas turunan yang mengambil alih GetHashCode() juga harus mengambil alih Equals(Object) untuk menjamin bahwa dua objek yang dianggap sama memiliki kode hash yang sama; jika tidak, jenisnya Hashtable mungkin tidak berfungsi dengan benar.