Che tipo di membri dovrebbero essere utilizzati in un'implementazione GetHashCode ()

7

Stiamo creando alcuni analizzatori di Roslyn riguardanti GetHashCode() , incluso un analizzatore che lo implementa per te in una determinata classe.

Durante le ricerche sull'argomento abbiamo rilevato che ci sono molte considerazioni da prendere in considerazione, principalmente su quale tipo di membri dovrebbero essere evitati in un'implementazione GetHashCode() .

Il tipo principale di membri da evitare sono membri mutabili (per evitare le modifiche al codice hash quando vengono utilizzate in una raccolta).

In general, for mutable reference types, you should override GetHashCode only if:

  • You can compute the hash code from fields that are not mutable

[Source]

Ora la domanda che rimane: che tipo di membri stiamo parlando allora? Il membro deve essere immutabile, ma anche in questo caso dovrebbe essere (idealmente) diverso per ogni istanza, altrimenti ti ritroverai con lo stesso codice hash per ogni oggetto.

Questo mi porta a concludere che gli unici membri accettabili per un'implementazione GetHashCode() sono structly immutable structs e classi readonly immutable Nota: not const . Allo stesso modo, nessun campo static poiché sarebbero uguali in tutte le istanze comunque.

Il modo in cui questo sarebbe implementato nella realtà sarebbe usando un

  • Campo: readonly T myField
  • Proprietà: T myProp { get; }

Dato che non sarebbe possibile determinare se una classe è immutabile, dovremmo probabilmente eliminarla del tutto a parte forse da string .

Questo lascia l'elenco dei membri applicabili per un'implementazione GetHashCode() a:

  • Campi di sola lettura
  • Proprietà getter-only
  • Sono strutture immutabili
  • E non sono static
  • E non sono interfacce
  • + string

Sembra corretto o ho fatto un errore nel processo di pensiero da qualche parte? Sembra che all'improvviso ci siano molti meno campi di quelli che le persone normalmente usano. Mi rendo conto che c'è un aspetto pragmatico a questo che dice semplicemente "aggiungi tutti i campi e lascia che sia lo sviluppatore a capirlo", ma cerco di evitare di introdurre bug nascosti negli analizzatori.

    
posta Jeroen Vannevel 04.05.2016 - 21:56
fonte

1 risposta

4

Readonly fields

Questo è ovvio.

And getter-only properties

Sì, a patto che per "proprietà getter-only" intendiamo esclusivamente type prop { get; }

That are immutable structs

Sì, nel senso che anche le primitive in C # vengono implementate come strutture immutabili.

And aren't static

Questo è ovvio.

And aren't interfaces

Anche questo è ovvio, ma tieni presente che puoi sempre coinvolgere l'hashcode di identità di un'interfaccia, se necessario.

  • string

Di nuovo, è ovvio.

Il fatto che ti stia chiedendo con esattezza come implementare GetHashCode() può essere indicativo di confusione su quando implementare GetHashCode() e quando no. Esistono due tipi di oggetti:

  • Oggetti con semantica del valore
  • Oggetti con semantica di riferimento ("oggetto")

Gli oggetti con semantica del valore vengono utilizzati per la memorizzazione dei valori. Devono sempre essere immutabili e devono sempre implementare GetHashCode() prendendo in considerazione ogni singolo membro.

Gli oggetti con semantica di riferimento contengono la logica e in genere alcuni stati. Di solito non sono immutabili (sebbene sia possibile in rare circostanze), ma una cosa certa è che non saranno mai usati come valori, quindi non hanno mai bisogno di sovrascrivere il default GetHashCode() implementazione di object , che restituisce l'hashcode dell'identità dell'oggetto.

    
risposta data 04.05.2016 - 23:00
fonte

Leggi altre domande sui tag