2010-02-10 17 views
5

ich eine generische Klasse erschaffe Widgets zu halten und ich habe Probleme mit der Umsetzung der enthält Methode:Kann nicht generisch vergleichen Werte

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

Fehler: Operator ‚==‘ nicht auf die Operanden des Typs angewendet werden kann ' V 'und' V '

Wenn ich Typen nicht vergleichen kann, wie soll ich das implementieren? Wie machen Wörterbücher, Listen und all die anderen generischen Container es?

+0

möglich Duplikat [Kann nicht Operator beseitigen == sein auf generische Typen in C# angewendet?] (http://stackoverflow.com/questions/390900/canto-operator-be-applied-to-generic-types-in-c) – nawfal

Antwort

7

Sie haben ein paar Optionen hier

Die erste ist die Verwendung Object.Equals:

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

Seien Sie vorsichtig mit dieser Option; Wenn BObject.Equals nicht überschreibt, dann ist die Standardkomparation die Referenzgleichheit, wenn B ein Referenztyp und Wertgleichheit ist, wenn B ein Werttyp ist. Dies ist möglicherweise nicht das Verhalten, das Sie suchen, weshalb ich ohne weitere Informationen eine der nächsten beiden Optionen in Erwägung ziehen würde.

Die zweite ist eine Einschränkung hinzuzufügen, dass B ist IComparable:

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

dass so

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

Eine dritte ist eine IEqualityComparer<B> erfordern an den Konstruktor WidgetBox

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

Dann:

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

Mit dieser letzten Option können Sie eine Überlastung kann, dass standardmäßig EqualityComparer<T>.Default:

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

Abhängig von der Art und ob Sie nur daran interessiert sind Gleichheit (vs weniger als/größer als/gleich/etc) ist es in der Regel viel effizienter, einen IEqualityComparer im Gegensatz zu IComparer zu verwenden, da Gleichheit oft sehr schnell ausgeschlossen werden kann, wie bei Strings von verschiedenen ent Längen. – Josh

3

Nicht alle Objekte implementieren == aber alle haben Equals (obwohl sie von Object.Equals geerbt werden können).

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

zur Compile-Zeit, gibt es keine Garantie, dass die Art in der Art Argument B einen Gleichheitsoperator zur Verfügung stellt.

Stattdessen können Sie dies tun:

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

zu Jasons Antwort hinzuzufügen, können Sie auch hinzufügen, where T : IEquatable<T> statt IComparable. Dies führt zu einer Überlastung der Equals-Methode, die einen T-Parameter akzeptiert.

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)) 
     ... 
    } 
} 

Dies könnte die mitgelieferte Object.Equals Verfahren einfach verwenden, bevorzugt sein, da diese Referenzen für die Gleichwertigkeit von zwei Objekt prüft (glaube ich) und so könnte durchaus die Funktionalität, die Sie nicht liefern wollen (z, wenn Sie zwei Person Objekte mit der gleichen SSN Eigenschaft wollen, die als gleich angesehen werden, oder etwas Ähnliches).

Aber um Ihre Frage zu beantworten "wie machen alle .NET-Sammlungen es", glaube ich, die Equals Methode (keine Einschränkung) ist Ihre Antwort.

0

Wenn Sie mit ihm in Ihrem Fall wegkommen können dann alle es ist eine Klasse Einschränkung für B nimmt

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

, dass das Problem