Tengo una clase que es IComparable:
public class a : IComparable
{
public int Id { get; set; }
public string Name { get; set; }
public a(int id)
{
this.Id = id;
}
public int CompareTo(object obj)
{
return this.Id.CompareTo(((a)obj).Id);
}
}
Cuando agrego una lista de objetos de esta clase a un conjunto de hash:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);
Todo está bien y ha.countestá 2, pero:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));
Ahora ha.countes 3.
- ¿Por qué no
HashSetrespetaaelCompareTométodo? - ¿Es
HashSetla mejor manera de tener una lista de objetos únicos?

IEqualityComparer<T>en el constructor o impleméntelo en la clasea. msdn.microsoft.com/en-us/library/bb301504(v=vs.110).aspxRespuestas:
Utiliza un
IEqualityComparer<T>(aEqualityComparer<T>.Defaultmenos que especifique uno diferente en la construcción).Cuando agrega un elemento al conjunto, encontrará el código hash usando
IEqualityComparer<T>.GetHashCodey almacenará tanto el código hash como el elemento (después de verificar si el elemento ya está en el conjunto, por supuesto).Para buscar un elemento, primero usará
IEqualityComparer<T>.GetHashCodepara encontrar el código hash, luego, para todos los elementos con el mismo código hash, usaráIEqualityComparer<T>.Equalspara comparar la igualdad real.Eso significa que tienes dos opciones:
IEqualityComparer<T>al constructor. Esta es la mejor opción si no puede modificarse aTsí mismo o si desea una relación de igualdad no predeterminada (por ejemplo, "todos los usuarios con una ID de usuario negativa se consideran iguales"). Esto casi nunca se implementa en el tipo en sí (es decir,Foono se implementaIEqualityComparer<Foo>), sino en un tipo separado que solo se usa para comparaciones.GetHashCodeyEquals(object). Idealmente, implemente tambiénIEquatable<T>en el tipo, particularmente si es un tipo de valor. El método de comparación de igualdad predeterminado llamará a estos métodos.Tenga en cuenta que nada de esto es en términos de una comparación ordenada , lo que tiene sentido, ya que ciertamente hay situaciones en las que puede especificar fácilmente la igualdad, pero no una ordenación total. Todo esto es lo mismo que
Dictionary<TKey, TValue>, básicamente.Si desea un conjunto que use el ordenamiento en lugar de solo las comparaciones de igualdad, debe usarlo
SortedSet<T>desde .NET 4, que le permite especificar un enIComparer<T>lugar de unIEqualityComparer<T>. Esto usaráIComparer<T>.Compare, lo que delegaráIComparable<T>.CompareTooIComparable.CompareTosi está usandoComparer<T>.Default.fuente
IEqualityComparer<T>.GetHashCode/Equals()es implementarEqualsyGetHashCodesobreTsí mismo (y mientras lo hace, también implementaría la contraparte fuertemente tipada : -bool IEquatable<T>.Equals(T other))EqualsyGetHashCodesea suficiente, como se menciona en la respuesta de @ tyriker.IComparable(oIComparerpara el caso) no se le debe pedir que implemente la igualdad por separado (sino soloGetHashCode). En cierto sentido, las interfaces de comparabilidad deben heredar de las interfaces de igualdad. Entiendo los beneficios de rendimiento al tener dos funciones separadas (donde puede optimizar la igualdad por separado simplemente diciendo si algo es igual o no) pero aún así. Muy confuso de lo contrario cuando ha especificado cuándo las instancias son iguales enCompareTofunción y marco no considerará ese.a.boolProp == b.boolProp ? 1 : 0o debería sera.boolProp == b.boolProp ? 0 : -1oa.boolProp == b.boolProp ? 1 : -1. Yuk!Aquí hay una aclaración sobre una parte de la respuesta que no se ha dicho: el tipo de objeto de tu
HashSet<T>no tiene que implementarse,IEqualityComparer<T>sino que solo debe anularseObject.GetHashCode()yObject.Equals(Object obj).En lugar de esto:
Tu hiciste esto:
Es sutil, pero esto me hizo tropezar la mayor parte del día tratando de hacer que HashSet funcione de la manera prevista. Y como han dicho otros,
HashSet<a>terminará llamandoa.GetHashCode()ya.Equals(obj)según sea necesario cuando trabaje con el conjunto.fuente
bool IEquatable<T>.Equals(T other)para un ligero aumento de la eficiencia, pero lo más importante es el beneficio de la claridad. Por razones obvias, además de la necesidad de implementarGetHashCodejuntoIEquatable<T>, el documento de IEquatable <T> menciona que, para fines de coherencia, también debe anular elobject.Equalsde coherenciaovveride getHashcodeobras, perooverride bool equalsobtiene el error: ningún método encontraron a anulación. ¿alguna idea?public class a : IEqualityComparer<a> {, y luegonew HashSet<a>(a).HashSetusosEqualsyGetHashCode().CompareToes para conjuntos ordenados.Si desea objetos únicos, pero no le importa su orden de iteración,
HashSet<T>suele ser la mejor opción.fuente
El constructor HashSet recibe el objeto que implementa IEqualityComparer para agregar un nuevo objeto. si desea utilizar el método en HashSet, debe anular Equals, GetHashCode
fuente