2012-12-28 10 views
8

Jeśli jeden z wyliczeń jest przechowywany wewnątrz typu agregatu, można to uwzględnić w haszowaniu typu (przy założeniu typowej funkcji mieszania "multiply by primes"). Jeśli ktoś po prostu zadzwoni pod numer SomeEnum.GetHashCode(), wydaje się, że JIT umieszcza instancję, nawet w kompilacjach wydań.W jaki sposób można uzyskać kod skrótu wyliczenia bez boksowania go?

Profilowanie pokazuje, że około 10% czasu w mojej aplikacji spędził wyliczenia boksu w różnych funkcjach GetHashCode.

Kilka typów wartości implementuje IEquatable lub podobnych interfejsów, co umożliwia wywoływanie GetHashCode jako metody statycznej; co pozwala uniknąć boksowania. Ale System.Enum nie zapewnia przeciążenia statycznego GetHashCode. Czy istnieje jakiś sposób obliczania kodu, który powinien zostać użyty, ale który unika boksowania?

+2

Po co w ogóle kłopotać? Enum to własny kod skrótu. Wystarczy rzucić na int i nazwać to dziennie. –

+0

@Raymond: Pomyślałem, że może to doprowadzić do złej dystrybucji; ale zastanawiając się nad tym jeszcze raz, sprawdzę, czy to działa. –

+0

@Raymond: To rzeczywiście działa w tym konkretnym przypadku testowym. Zostawiam to otwarte przez jakiś czas ... –

Odpowiedz

4

Można rzucać do podstawowej typu enum (zwykle int chyba że definicja enum określa inaczej) i używać nadpisane GetHashCode() metody tego typu jest.

enum TestEnum 
{ 
    Test1, 
    Test2 
} 

TestEnum t = TestEnum.Test1; 
((int)t).GetHashCode(); // no boxing 
t.GetHashCode(); // boxing 

Oto IL dla tego kodu:

IL_0000: nop 
IL_0001: ldc.i4.0 
IL_0002: stloc.0 
IL_0003: ldloc.0 
IL_0004: stloc.1 
IL_0005: ldloca.s V_1 
IL_0007: call  instance int32 [mscorlib]System.Int32::GetHashCode() 
IL_000c: pop 
IL_000d: ldloc.0 
IL_000e: box  ConsoleApplication1.Program/TestEnum 
IL_0013: callvirt instance int32 [mscorlib]System.Object::GetHashCode() 
IL_0018: pop 
IL_0019: ret 

Edit: Dla uzupełnienia należy wskazać, że ciało int.GetHashCode() jest po prostu return this;, tak jak Raymond Chen wskazano w komentarz powyżej, wystarczy rzucić enum do int jest wystarczająco dobry, aby uzyskać kod skrótu.

+0

Czy to w rzeczywistości pozwala uniknąć boksu? (np. czy 'int.GetHashCode()' również nie skutkuje boksowaniem?) –

+0

Tak, to pozwala uniknąć boksowania. Rzucanie z enumu na int unika boksowania (odwołaj się do pierwszego komentarza Jona Skeeta: http://bytes.com/topic/c-sharp/answers/276556-enum-vs-constants-performance) i wywołanie GetHashCode na int nie powoduje boksowania, ponieważ GetHashCode jest nadpisany dla tej struktury (i nawet dekompilowałem jego implementację i nie robi nic, co mogłoby spowodować operację boksu). Wywoływanie wersji Enum GetHashCode w rzeczywistości powoduje boksowanie (jak już wspomniano), ponieważ wywołuje wewnętrzną metodę, która zwraca 'obiekt', a następnie wywołuje' GetHashCode() 'na niej. – jam40jeff

+0

Nawiasem mówiąc, błędnie sprawdziłem implementację 'GetHashCode()' dla 'short' przed opublikowaniem. Implementacja 'int' jest po prostu' return this; ', więc (jak już powiedział Raymond Chen) możesz po prostu rzucić wartość Enum do' int' i użyć tego jako swojego kodu skrótu. – jam40jeff

Powiązane problemy