Overriding Uguale in un modo unbrittle

6

Ho una classe WorkflowItemSearchCriteria le cui istanze rappresentano un insieme di valori e riferimenti che verranno utilizzati per restituire un set di risultati filtrato di elementi del flusso di lavoro in base ai criteri di ricerca specificati.

class WorkflowItemSearchCriteria
{
    string ID { get; set; }
    Client TargetClient { get; set; }
    Person Supervisor { get; set; }
    Person WorkingAttorney { get; set; }
    SearchDateKind? TargetSearchDateKind { get; set; }
    DateTime? FromDate { get; set; }
    DateTime? ToDate { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is WorkflowItemSearchCriteria)) return false;
        var target = (WorkflowItemSearchCriteria) obj;
        if (!target.ID.Equals(this.ID)) return false;
        if (target.TargetClient != this.TargetClient) return false;
        if (target.Supervisor != this.Supervisor) return false;
        if (target.WorkingAttorney != this.WorkingAttorney) return false;
        if (!target.TargetSearchDateKind.Equals(this.TargetSearchDateKind)) return false;
        if (!target.FromDate.Equals(this.FromDate)) return false;
        if (!target.ToDate.Equals(this.ToDate)) return false;
        return true;
    }

    public override int GetHashCode()
    {
        // According to MSDN, two objects that are equal must return the same hash code,
        // but the same hash code does not mean two objects are equal.  If two value 
        // objects are equal, then all property and field values must be equal,
        // so it's sufficient to return the hash code from just ONE field or property
        // because it will equal the hash code from another object that is equal to it.
        return ID.GetHashCode();
    }

    enum SearchDateKind
    {
        DateCreated,
        DateCompleted
    }
}

Ad un certo punto, voglio confrontare due istanze di questa classe per l'uguaglianza value-wise, quindi sto sovrascrivendo Equals come mostrato. Ho letto fonti come questo per aiutarmi, ma sento ancora che il modo in cui produco risultati in codice fragile perché i futuri sviluppatori dovrebbero ricordarsi di aggiornare il sovraccarico Equals se ci fossero mai aggiunte a WorkflowItemSearchCriteria .

C'è un approccio migliore a questo?

    
posta rory.ap 29.12.2015 - 15:17
fonte

3 risposte

2

Un approccio a questo problema consiste nell'aggiungere un test unitario che verifica la corretta uguaglianza. Il test unitario potrebbe utilizzare la riflessione per enumerare ogni proprietà, costruire oggetti con una sola proprietà non uguale e verificare che l'uguaglianza la gestisca correttamente.

Uno strumento come Microsoft Pex può fare un passo avanti, in modo esauriente (algoritmicamente, non tramite forza bruta) controllando tale uguaglianza. Tuttavia, risolvere questo problema con Pex è probabilmente sia difficile che eccessivo.

Un approccio alternativo consiste nell'utilizzare una sorta di strumento di analisi statica che risolve questo problema, ma non sono sicuro che esistano strumenti adeguati per questo scenario.

    
risposta data 29.12.2015 - 19:20
fonte
1

Al momento mi manca un po 'di sonno, quindi darò una risposta approssimativa.

Puoi annotare i membri rilevanti per l'uguaglianza con un tuo attributo personalizzato, come [EqualityMember] , e nel metodo Equals puoi eseguire i confronti usando la riflessione. Dovresti eseguire la scansione del tipo per i campi / altri membri decorati con l'attributo utilizzando GetCustomAttribute<EqualityMember>() != null .

Potresti anche diventare più pazzo e avere l'attributo specificare come avvicinarsi all'uguaglianza. Che tipo di confronto usare. Gli attributi sono davvero accurati.

Poiché i membri del tipo non cambieranno, è possibile memorizzare gran parte del lavoro di riflessione e riutilizzarlo. Dubito che le prestazioni saranno un problema, ma potresti persino costruire un albero di espressioni e compilarlo, anche se sembra un mal di testa.

Ho appena realizzato, l'ho già fatto prima. Ma non ricordo quando o perché ...

    
risposta data 04.01.2016 - 20:25
fonte
0

Puoi anche includere Fody Equals , che inietta la logica Equals (incluso IEquatable<T> e overloading operatori == e != ) in fase di compilazione.

Devi solo aggiungere l'attributo Equals :

[Equals]
class WorkflowItemSearchCriteria
{
    //...
}
    
risposta data 05.01.2016 - 18:13
fonte

Leggi altre domande sui tag