2010-06-09 14 views
8

Powiedziano mi, że jednym z wielu powodów, dla których napisy zostały uczynione niezmiennymi w specyfikacji C#, było uniknięcie wydania HashTables z kluczami zmienionymi, gdy odwołania do klawiszy string zmieniły ich zawartość.C# Dictionary <> i zmienne klawisze

Słownik <> typ umożliwia użycie typów odniesienia jako klucza. W jaki sposób słownik unika problemu zmienionych kluczy, które prowadzą do "niewłaściwie umieszczonych" wartości? Czy istnieje kliencki klon utworzony z obiektu, gdy jest używany jako klucz?

Odpowiedz

9

Typ Dictionary<TKey,TValue> nie podejmuje prób ochrony użytkownika przed modyfikacją użytego klucza. Tylko autor nie ponosi odpowiedzialności za mutację klucza.

Jeśli myślisz o tym trochę, to jest to jedyna rozsądna droga, którą może przyjąć Dictionary<TKey,TValue>. Rozważ implikację wykonania operacji podobnej do klonu członkowskiego na obiekcie. Aby być dokładnym, musisz wykonać głęboki klon, ponieważ będzie możliwe, że obiekt, do którego odnosi się ten klucz, również zostanie zmutowany i tym samym wpłynie na kod skrótu. Teraz każdy klucz użyty w tabeli ma swój pełny obiekt, klonowany w celu ochrony przed mutacją. Byłaby to zarówno błędna, jak i bardzo kosztowna operacja.

+1

Python przeszedł jednak inną drogę, a zmienne dane nie są dozwolone jako klucz pamięci podręcznej. http://www.udacity.com/view#Course/cs212/CourseRev/apr2012/Unit/207010/Nugget/251006 –

5

Klasa Dictionary<> nie chroni się przed zmianą zmieniającego się klucza. Od Ciebie zależy, czy klasa, której używasz jako klucza, jest zmienna, i jeśli to możliwe, unikaj jej.

3

Nie unika tej sytuacji. To do kodu wywołującego do egzekwowania tego:

Dopóki obiekt jest używany jako klucz w Dictionary<TKey, TValue>, musi nie zmienia w żaden sposób, który wpływa na jego wartość hash. Każdy klucz w Dictionary<TKey, TValue> musi być unikalny zgodnie ze słownikowym porównywarką równości. Klucz nie może być null, ale wartość może być, jeśli typ wartości TValue jest typem odniesienia.

(Od MSDN)

8

Jeśli używasz zmienny typ referencyjny jako klucz, wdrożenie domyślna GetHashCode() gwarantuje równość hash niezależnie od stanu obiektu (czyli hash jest związana z odniesienie, a nie stan). Masz jednak rację, że zmienny typ z semantyką równości wartości (gdzie GetHashCode prawdopodobnie zależy od stanu) jest złym wyborem dla klucza słownika.

+0

To jest dobre.Dziękuję za przypomnienie sobie, że domyślnie GetHashCode dla obiektu opiera się na instancji, która moim zdaniem oszczędza deweloperom dużo czasu. –

+0

Zmutowane typy klas z wartościową semantyką równości i tak wydają się złym pomysłem. Chociaż istnieje kilka wyjątków (np. 'Double',' Decimal', 'List .Eumerator', itp.), Większość typów w .net implementuje' Równa się (Obiekt) ', aby wskazać równoważność; ponieważ różne zmienne elementy typu class nigdy nie są równoważne, nigdy nie powinny się zgłaszać jako "Equals" (zachowanie listy "List .Eumerator" wynika z faktu, że typy wartości w pudełkach i bez zawartości mają inną semantykę, ale są wymagane do współdzielenia ta sama metoda "równa się"). – supercat

3

Jeśli typ odniesienia nie zastępuje Equals/GetHashCode, słownik korzystający z domyślnego komparatora nie będzie dbał o żadne z pól lub właściwości kluczowych obiektów, a zatem nie zauważy lub nie będzie się przejmował, czy ulegną one zmianie. Najprościej jest pomyśleć o domyślnej metodzie GetHashCode zwracającej liczbę związaną z "identyfikatorem obiektu", a domyślną metodą Equals jako porównującą "id obiektu". Rzeczywiście, w systemie ograniczonym do dwóch miliardów lub mniej obiektów, GetHashCode może po prostu zwrócić identyfikator obiektu, ale z różnych powodów może również robić inne rzeczy.

Jeśli jedyną częścią obiektu zbadaną przez Equals lub GetHashCode jest identyfikator obiektu, to dla celów tych funkcji wszystkie obiekty są niezmienne. Gdy obiekt zostanie utworzony, zawsze będzie miał ten sam identyfikator i ten identyfikator nigdy nie będzie używany dla żadnego innego obiektu, dopóki wszystkie ślady dawnego identyfikatora obiektu nie znikną ze wszechświata.

Powiązane problemy