2010-06-09 6 views
8

Tôi đã nói rằng một trong nhiều lý do chuỗi đã được thực hiện bất biến trong C# spec là để tránh vấn đề HashTables có phím thay đổi khi tham chiếu đến các phím chuỗi thay đổi nội dung của họ.C# Dictionary <> và các khóa có thể thay đổi

Từ điển <> loại cho phép loại tham chiếu được sử dụng làm khóa. Làm thế nào để từ điển tránh vấn đề các phím bị thay đổi dẫn đến các giá trị "không đúng chỗ"? Có một bản sao thành viên được tạo thành từ một đối tượng khi được sử dụng làm khóa không?

Trả lời

9

Loại Dictionary<TKey,TValue> không cố gắng bảo vệ chống lại người dùng sửa đổi khóa được sử dụng. Nó hoàn toàn là trái với các nhà phát triển chịu trách nhiệm trong việc không biến đổi chìa khóa.

Nếu bạn nghĩ về điều này một chút, đây thực sự là tuyến đường lành mạnh duy nhất mà Dictionary<TKey,TValue> có thể thực hiện. Hãy xem xét ý nghĩa của việc thực hiện một thao tác giống như một bản sao thành viên trên đối tượng. Để được triệt để bạn cần phải làm một bản sao sâu vì nó sẽ có thể cho một đối tượng được tham chiếu trong khóa cũng bị biến đổi và do đó ảnh hưởng đến mã băm. Vì vậy, bây giờ tất cả các phím được sử dụng trong bảng có đầy đủ đồ thị đối tượng nhân bản để bảo vệ chống đột biến. Đây sẽ là cả hai lỗi và có thể là một hoạt động rất tốn kém.

+1

Python mặc dù đã đi theo một cách khác và dữ liệu có thể thay đổi không được phép làm khóa bộ nhớ cache. http://www.udacity.com/view#Course/cs212/CourseRev/apr2012/Unit/207010/Nugget/251006 –

5

Lớp Dictionary<> không có gì để tự bảo vệ chống lại một đối tượng khóa có thể thay đổi được thay đổi. Tùy thuộc vào bạn có biết lớp học bạn đang sử dụng làm khóa có thể thay đổi hay không và để tránh nó nếu có thể.

3

Nó không tránh tình trạng này. Tùy thuộc vào mã gọi để thực thi điều này:

Miễn là đối tượng được sử dụng làm khóa trong Dictionary<TKey, TValue>, nó không được thay đổi theo bất kỳ cách nào ảnh hưởng đến giá trị băm của nó. Mỗi khóa trong một Dictionary<TKey, TValue> phải là duy nhất theo so sánh bình đẳng của từ điển. Khóa không thể là null, nhưng giá trị có thể là, nếu loại giá trị TValue là loại tham chiếu.

(Từ MSDN)

8

Nếu bạn đang sử dụng một loại tài liệu tham khảo có thể thay đổi như một chìa khóa, việc thực hiện mặc định của GetHashCode() sẽ đảm bảo bình đẳng băm bất kể trạng thái đối tượng (tức là băm được gắn với tham chiếu, không phải trạng thái). Tuy nhiên, bạn đúng là một loại có thể thay đổi được với ngữ nghĩa bình đẳng giá trị (trong đó GetHashCode có lẽ phụ thuộc vào trạng thái) là một lựa chọn không hợp lệ đối với khóa từ điển.

+0

Đây là một câu hỏi hay.Cảm ơn bạn đã nhớ tôi rằng GetHashCode cho một đối tượng theo mặc định được dựa trên trường hợp mà tôi nghĩ rằng các nhà phát triển tiết kiệm rất nhiều thời gian. –

+0

Các loại lớp có thể thay đổi với ngữ nghĩa bình đẳng giá trị dường như là một ý tưởng tồi. Mặc dù có một vài ngoại lệ (ví dụ: 'double',' Decimal', 'List .Enumerator', v.v.), hầu hết các loại trong .net đều thực hiện' Equals (Object) 'để chỉ ra sự tương đương; vì các hạng mục loại có thể biến đổi không bao giờ tương đương, chúng không bao giờ tự báo cáo là 'Equals' (hành vi của' List .Enumerator' bắt nguồn từ thực tế là các loại giá trị đóng hộp và không có hộp có ngữ nghĩa khác nhau, nhưng được yêu cầu chia sẻ cùng phương thức 'Equals'). – supercat

3

Nếu loại tham chiếu không ghi đè bằng/GetHashCode, từ điển sử dụng trình so sánh mặc định sẽ không quan tâm đến bất kỳ trường hoặc thuộc tính nào của đối tượng khóa và do đó sẽ không nhận thấy hoặc quan tâm nếu chúng thay đổi. Cách đơn giản nhất để nghĩ về phương thức GetHashCode mặc định là trả về một số liên quan đến "ID đối tượng" và phương thức Equals mặc định khi so sánh "id đối tượng". Thật vậy, trong một hệ thống giới hạn ở hai tỷ hoặc ít hơn các đối tượng, GetHashCode có thể đơn giản trả về một ID đối tượng, nhưng vì nhiều lý do nó có thể làm những việc khác nữa.

Nếu phần duy nhất của đối tượng được kiểm tra bằng Bằng hoặc GetHashCode là ID đối tượng, sau đó cho mục đích của các hàm đó, tất cả các đối tượng đều không thay đổi. Khi một đối tượng được tạo, nó sẽ luôn có cùng một ID và ID đó sẽ không bao giờ được sử dụng cho bất kỳ đối tượng nào khác cho đến khi tất cả các dấu vết của ID đối tượng cũ đã biến mất khỏi vũ trụ.