Posso applicare l'override dei metodi GetHashCode () ed Equals () per gli utenti di una classe contenitore generica?

1

Ho una classe contenitore simile a quella sottostante (con molta della logica omessa):

class Container<T>
{
    Dictionary<T, TWrapped> contains = new Dictionary<T, TWrapper>();

    public void Add(T item)
    {
        TWrapped wrappedItem = new TWrapped(item);
        contains[item] = wrappedItem;

        // logic involving wrappedItem...
    }

    public bool Contains(T item)
    {
        return contains.ContainsKey(item);
    }

    // Item has been updated, so Sort called on container
    public void Sort(T item)
    {
        TWrapped wrappedItem;
        if(contains.TryGetValue(item, out wrappedItem))
        {
            // sort the wrappedItem within the container...
        }
    }

}

C'è un modo per dire agli utenti di Container che T verrà usato come chiave di dizionario o, in modo equivalente, di forzare gli utenti ad avere GetHashCode () e Equals () sovrascritti?

Altre informazioni

La mia attuale classe contenitore implementa un heap implicitamente con un array. Per fare ciò, gli articoli sono avvolti con una classe che contiene informazioni sugli indici per trovare genitori e figli all'interno dell'array. Questa classe wrapper è privata all'interno dell'heap per evitare manomissioni involontarie dei valori dell'indice.

Ora desidero supportare il riordinamento di elementi specifici nell'heap; tuttavia, per mappare dall'elemento fornito dall'utente alla sua rappresentazione avvolta nell'array, ho bisogno di un dizionario per memorizzare tale mappatura ... da qui i guai GetHashCode () Equals ().

Qualsiasi critica al design sarebbe gradita!

    
posta Jack 21.01.2016 - 21:50
fonte

1 risposta

3

Per quanto riguarda i tipi di riferimento (classi), sei già ok dato che hanno Equals e GetHashCode implementati correttamente anche senza eseguire l'override.

Quando si tratta di tipi di valore (structs, enum, ...), questi devono sempre sovrascrivere Equals e GetHashCode in modo significativo ed essere immutabili secondo le linee guida di progettazione MSDN - struct dovrebbe implementare IEquatable<T>; e transitivamente IEquatable<T> dovrebbe sovrascrivere GetHashCode e Equals (Note per la parte implementatori).

Se vuoi davvero esprimere questo requisito al consumatore, considera l'aggiunta di un seguente vincolo generico:

public class Container<T> where T : IEquatable<T>

Questo probabilmente causerà solo fastidio ai consumatori, dato che saranno costretti a implementare inutilmente IEquatable<T> sulle classi.

Un'altra opzione è forzare ogni consumatore a fornire un IEqualityComparer<T> al tuo Container<T> che verrà quindi utilizzato da Dictionary :

public class Container<T>
{
     private Dictionary<T, TWrapped> _contains;

     public Container(IEqualityComparer<T> comparer)
     {
         _contains = new Dictionary<T, TWrapped>(comparer);
     }

     // rest of implementation...
}

Presumibilmente, la maggior parte dei consumatori lo farà

var container = new Container<T>(EqualityComparer<T>.Default);

ma è bello rispecchiare in qualche modo i cori di Dictionary per una maggiore flessibilità. Potrei fare

se volessi delle chiavi stringa insensibili alle maiuscole ordinali
var container = new Container<string>(StringComparer.OrdinalIgnoreCase);
    
risposta data 21.01.2016 - 22:02
fonte

Leggi altre domande sui tag