2009-09-30 16 views
6

Ho un modello di dominio che è banalmente rappresentato dal seguente.Implementazione IEquatable <T> dove T è un'interfaccia

IMyInterface 

ClassA : IMyInterface 

ClassB : IMyInterface 

Quello che voglio è implementare IEquatable in modo tale da poter scrivere codice come qualcosa.

if(dynamicallyCreatedInstanceOfClassA == dynamicallyCreatedinstanceOfClassB) 
{ 
    // Do something relevant 
} 

Il mio primo istinto era quello di avere IMyInterface implementare IEquatable ma naturalmente non può realmente fare la attuazione in IMyInterface. Dovrei farlo in ClassA e ClassB. Ciò che mi colpisce di questa soluzione è che le implementazioni di IEquatable in ClassA e ClassB saranno esattamente, linea per linea uguale. C'è un modo elegante per realizzare questo? Quando arriva ClassC non voglio dover copiare e incollare 50 righe di codice IEquatable duplicato.

Ho considerato l'utilizzo di una classe base astratta anziché un'interfaccia, ma in questo scenario IMyInterface descrive solo le azioni che la classe eseguirà e non ciò che la classe è. ClassA e ClassB non condividono molte somiglianze, tranne che possono entrambe eseguire le azioni nel contratto IMyInterface.

Qualsiasi approfondimento è utile, e grazie per il vostro tempo.

+0

Avrei anche suggerito di seguire la via astratta, ma lo svantaggio è che limiterà le classi derivate dall'erogare da un'altra classe concreta poiché MI non è consentito in C#.Vedi la risposta di supercat per vedere il potenziale problema che coinvolge 'GetHashCode'. L'approccio di Jon è l'unica via facile che sembra .. – nawfal

+1

@nawfal: l'approccio di Jon è quello giusto, poiché è del tutto normale e previsto per un 'IEqualityComparer ' per rappresentare forme piuttosto ampie di equivalenza che 'T' potrebbe non sapere nulla di. Ad esempio, due oggetti che si verificano per implementare 'IList ' dovrebbero probabilmente riportarsi uguali tra loro se contengono sempre gli stessi elementi nello stesso ordine. Può essere utile, tuttavia, che un oggetto sia in grado di memorizzare gli elenchi che possiede in un 'Dictionary , whaever>', dove gli elenchi contenenti gli stessi elementi in qualsiasi sequenza saranno comparabili. – supercat

+1

@nawfal: non esiste un metodo di confronto simile in 'IList '; le implementazioni generalmente non ne forniscono neanche uno. Ciononostante, un tale metodo di confronto può essere utile in alcuni contesti, quindi sarebbe perfettamente ragionevole usare una classe esterna per implementare un 'ICEqualityComparer >' in questo modo. – supercat

risposta

7

Invece di implementare IEquatable<T>, potresti forse implementare IEqualityComparer<T> in una classe separata? Nella maggior parte dei casi in cui sei interessato all'uguaglianza, puoi invece specificare un comparatore, e sospetto che sarà più pulito in questo modo.

+0

Questa è una buona idea Jon, grazie per l'input. Ho appena letto C# in profondità e mi ha insegnato un sacco di cose sulla lingua che non avevo mai considerato prima. Lo leggerò una seconda volta immediatamente solo per cercare di assorbire tutto. –

+0

@Matthew: potresti voler aspettare che la seconda edizione sia pronta per una seconda lettura, altrimenti dovrai leggerlo tutto * tre * volte :) –

+0

Questo è un buon punto, qual è l'eta della seconda edizione? –

0

Penso che se l'interfaccia non può essere convertita in una classe astratta, non ha molto senso confrontare le due classi implementate l'una con l'altra direttamente o automaticamente. Significa che implementare un confronto personalizzato su ogni classe sarebbe la strada da percorrere. Sono sicuro che puoi in qualche modo rifattare il codice comparativo per renderlo più semplice in seguito.

5

In base alla tua domanda sembra che tu sappia quale sarà l'algoritmo Equals e che sarà esattamente lo stesso sia per ClassA che per ClassB. Perché non fare quanto segue

  1. Definire IMyInterface di ereditare da IEquatable<IMyInterface>
  2. Definire un abstract MyInterfaceBase classe base che implementa IMyInterface e ha la IEquatable<IMyInterface> implementazione
  3. Hanno ClassA e ClassB derivano da MyInterfaceBase
+0

Anch'io ho pensato a questo, ho avuto paura che la classe A abbia bisogno di ereditare nel prossimo futuro per raggiungere altri obiettivi, posso ovviamente attraversare quel ponte quando arrivo ad esso, Se ho intenzione di percorrere questa strada Potrei anche solo ritagliare l'interfaccia e usare una classe base astratta. Nemmeno fuori questione. Grazie per l'input. –

1

Se IEquatable<T> incluso un membro GetHashcode() potrebbe essere possibile definire semantica significativi per tale tipo che differiva da Object.Equals (ad esempio "se si stavano guardando soltanto le caratteristiche che sono presenti in T, sarebbero gli oggetti considerati la stessa"). Perché non lo fa, tuttavia, in genere non ci sono molte ragioni per implementare lo IEquatable<T> tranne nei casi in cui può migliorare le prestazioni senza aggiungere alcuna semantica bizzarra. In pratica, ciò significa che lo IEquatable<T> deve essere implementato solo dallo T stesso (se T è una classe o una struttura sigillata) o non lo è affatto (se T è ereditabile, o se i vantaggi in termini di prestazioni non valgono lo sforzo).

+0

+1 per affrontare davvero il problema .. – nawfal

Problemi correlati