2010-02-10 12 views
5

Estoy creando una clase genérica para mantener widgets y tengo problemas para implementar el método contains:no se puede comparar Genérico Valores

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

error: Operador '==' no se puede aplicar a operandos de tipo ' V 'y' V '

Si no puedo comparar tipos, ¿cómo debo implementar? ¿Cómo lo hacen los diccionarios, las listas y todos los otros contenedores genéricos?

+0

posible duplicado de [Puede no ser operador == aplicado a los tipos genéricos en C#?] (http://stackoverflow.com/questions/390900/cant-operator-be-applied-to-generic-types-in-c) – nawfal

Respuesta

7

usted tiene algunas opciones aquí

La primera es utilizar Object.Equals:

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

Tenga cuidado al usar esta opción; si B no anula Object.Equals, la comparación por defecto es igualdad de referencia cuando B es un tipo de referencia e igualdad de valor cuando B es un tipo de valor. Puede que este no sea el comportamiento que está buscando y es por eso que sin información adicional consideraría una de las siguientes dos opciones.

El segundo es añadir una restricción que B es IComparable:

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

para que

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

Una tercera es para requerir una IEqualityComparer<B> ser pasado al constructor de WidgetBox

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

Luego:

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

Con esta última opción puede proporcionar una sobrecarga que por defecto es EqualityComparer<T>.Default:

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

Dependiendo del tipo y si solo te importan Igualdad (vs menor que/mayor que/igual/etc) es típicamente mucho más eficiente utilizar un IEqualityComparer en comparación con IComparer ya que la igualdad a menudo se puede descartar muy rápidamente, como con cadenas de diferir longitudes de ent. – Josh

3

No todos los objetos implementan == pero todos tendrán igual (aunque pueden heredarse de 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

en tiempo de compilación, no hay garantía de que el tipo en el tipo de argumento B proporciona un operador de igualdad.

En su lugar, usted puede hacer esto:

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

Para añadir a la respuesta de Jason, también se puede añadir where T : IEquatable<T> en lugar de IComparable. Esto proporciona una sobrecarga del método Equals que acepta un parámetro 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)) 
     ... 
    } 
} 

Esto podría ser preferible simplemente usando el método de Object.Equals suministrado, ya que comprueba la equivalencia de dos objetos referencias (creo) y por lo tanto no puede proporcionar bastante la funcionalidad que desee (por ejemplo,, si desea dos objetos Person con la misma propiedad SSN para ser considerados iguales, o algo así).

Pero para responder a su pregunta de "cómo lo hacen todas las colecciones .NET", creo que el método Equals (sin restricción) es su respuesta.

0

Si puede salirse con la suya en su caso, entonces todo lo que necesita es una restricción de clase B en

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

que eliminará el problema

Cuestiones relacionadas