2010-02-10 8 views
5

sto creando una classe generica per contenere i widget e sto avendo difficoltà attuazione del metodo contiene:non possono Confronta Generico Valori

public class WidgetBox<A,B,C> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b == iteratorB) // Compiler error. 
     ... 
    } 
} 

Errore: operatore '==' non può essere applicato a operandi di tipo ' V 'e' V '

Se non riesco a confrontare i tipi, come posso includerli? Come fanno i dizionari, gli elenchi e tutti gli altri contenitori generici?

+0

possibile duplicato del [Non può essere operatore == applicato a tipi generici in C#?] (http://stackoverflow.com/questions/390900/cant-operator-be-applied-to-generic-types-in-c) – nawfal

risposta

7

avete alcune opzioni qui

Il primo è quello di utilizzare Object.Equals:

if(b.Equals(iteratorB)) { 
    // do stuff 
} 

Fare attenzione usando questa opzione; se B non sovrascrive Object.Equals, il comparsion predefinito è l'uguaglianza di riferimento quando B è un tipo di riferimento e l'uguaglianza di valore quando B è un tipo di valore. Questo potrebbe non essere il comportamento che stai cercando ed è il motivo per cui senza ulteriori informazioni considererei una delle prossime due opzioni.

Il secondo è quello di aggiungere un vincolo che B è IComparable:

public class WidgetBox<A, B, C> where B : IComparable 

modo che

if(b.CompareTo(iteratorB) == 0) { 
    // do stuff 
} 

Un terzo è quello di richiedere un IEqualityComparer<B> essere passato al costruttore di WidgetBox

public class WidgetBox<A, B, C> { 
    IEqualityComparer<B> _comparer; 
    public WidgetBox(IEqualityComparer<B> comparer) { 
     _comparer = comparer; 
    } 
    // details elided 
} 

Quindi:

if(_comparer.Equals(b, iteratorB)) { 
    // do stuff 
} 

Con questa ultima opzione è possibile fornire un sovraccarico che il valore predefinito è EqualityComparer<T>.Default:

public WidgetBox() : this(EqualityComparer<T>.Default) { } 
+1

A seconda del tipo e se ti interessa solo uguaglianza (vs minore/maggiore di/uguale/ecc.) è in genere molto più efficiente utilizzare unComponente IE rispetto a IComparer poiché l'uguaglianza può essere spesso esclusa molto rapidamente, ad esempio con stringhe diverse lunghezze – Josh

3

Non tutti gli oggetti implementano == ma tutti avranno uguali (anche se potrebbero essere ereditati da Object.Equals).

public class WidgetBox<A,B,C> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b.Equals(iteratorB)) 
     ... 
    } 
} 
0
if (b != null) 
    if (b.Equals(iteratorB)) 
     ... 
2

Al momento della compilazione, non v'è alcuna garanzia che il tipo del tipo dell'argomento B fornisce un operatore di uguaglianza.

Invece, si può fare questo:

var comparer = EqualityComparer<B>.Default; 
foreach (B item in items) { 
    if (comparer.Equals(b, item)) { 
     .... 
    } 
} 
3

Per aggiungere alla risposta di Jason, è anche possibile aggiungere where T : IEquatable<T> piuttosto che IComparable. Ciò fornisce un sovraccarico del metodo Equals che accetta un parametro T.

public class WidgetBox<A,B,C> where B : IEquatable<B> 
{ 
    public bool ContainsB(B b) 
    { 
     // Iterating thru a collection of B's 
     if(b.Equals(iteratorB)) 
     ... 
    } 
} 

Questo potrebbe essere preferibile semplicemente utilizzando il metodo di Object.Equals fornito, dal momento che i controlli per l'equivalenza dei due oggetti riferimenti (credo) e quindi potrebbe non fornire abbastanza la funzionalità che si desidera (per esempio, se si desidera che due oggetti Person con la stessa proprietà SSN siano considerati uguali o qualcosa del genere).

Ma per rispondere alla domanda "come fanno tutte le raccolte .NET farlo", credo che il metodo Equals (nessun vincolo) sia la risposta.

0

Se si riesce a farla franca nel vostro caso allora tutto quello che serve è un vincolo classe B

public class WidgetBox<A,B,C> where B : class 

che eliminerà il problema

Problemi correlati