2012-12-28 12 views
8

Se si dispone di un'enumerazione memorizzata all'interno di un tipo di aggregazione, è possibile includerla all'interno del codice hash del tipo (presupponendo una tipica funzione di hash "multiply by primes"). Se si chiama semplicemente SomeEnum.GetHashCode(), sembra che il JIT inscatoli l'istanza, anche nelle versioni di rilascio.Come si recupera il codice hash di un'enumerazione senza inserirlo?

Il profilo mostra circa il 10% del tempo trascorso dalla mia applicazione in enumerazioni di boxe all'interno di varie funzioni GetHashCode.

Diversi tipi di valore implementano IEquatable o interfacce simili, che consente di chiamare GetHashCode come metodo statico; che evita il pugilato. Ma System.Enum non fornisce l'overload statico di GetHashCode. C'è qualche mezzo per calcolare il codice che dovrebbe essere usato ma che evita il pugilato?

+2

Perché preoccuparsi del tutto? L'enum è il proprio codice hash. Basta trasmettere a int e chiamarlo un giorno. –

+0

@ Raymond: ho pensato che potrebbe causare una cattiva distribuzione; ma ripensandoci, vedrò se funziona. –

+0

@ Raymond: Questo funziona davvero per questo particolare caso di test. L'ho lasciato aperto per un po '... –

risposta

4

Si potrebbe lanciare al tipo di fondo della enum (di solito int a meno che la definizione enum diversamente specificato) e utilizzare sovrascritto GetHashCode() metodo che di tipo.

enum TestEnum 
{ 
    Test1, 
    Test2 
} 

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

Ecco la IL per questo codice:

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: Per completezza, vorrei sottolineare che il corpo di int.GetHashCode() è semplicemente return this;, in modo da Raymond Chen ha sottolineato in un commento sopra, semplicemente la trasmissione dell'en a int è sufficiente per ottenere un codice hash.

+0

Questo in effetti evita il pugilato? (ad esempio, non 'int.GetHashCode()' comporta anche il pugilato?) –

+0

Sì, questo evita la boxe. Il cast da un enum a un int evita il pugilato (si veda il primo commento di Jon Skeet: http://bytes.com/topic/c-sharp/answers/276556-enum-vs-constants-performance) e chiamare GetHashCode su un int fa non causa la boxe poiché GetHashCode è sovrascritto per questa struttura (e ho persino decompilato la sua implementazione, e non fa nulla che possa causare un'operazione di boxe). Chiamare la versione Enum di GetHashCode causa infatti il ​​pugilato (come già notato) perché chiama un metodo interno che restituisce un 'oggetto', quindi chiama' GetHashCode() 'su di esso. – jam40jeff

+0

A proposito, ho erroneamente controllato l'implementazione di 'GetHashCode()' per 'short' prima di pubblicare. L'implementazione di 'int' è semplicemente' return this; ', quindi (come già commentato da Raymond Chen) puoi semplicemente convertire il valore Enum in un 'int' e usarlo come codice hash. – jam40jeff

Problemi correlati