Estoy tratando de escribir una consulta Linq que devuelve una matriz de objetos, con valores únicos en sus constructores. Para los tipos enteros, Distinct devuelve solo una copia de cada valor, pero cuando intento crear mi lista de objetos, las cosas se desmoronan. Sospecho que es un problema con el operador de igualdad para mi clase, pero cuando configuro un punto de interrupción, nunca se golpea.Distinct() devuelve duplicados con un tipo definido por el usuario
Al filtrar el duplicado int en una subexpresión resuelve el problema, y también me ahorra la construcción de objetos que se descartarán inmediatamente, pero me llama la atención por qué esta versión no funciona.
ACTUALIZACIÓN: 11:04 PM Varias personas han señalado que MyType no anula GetHashCode(). Me temo que simplifiqué demasiado el ejemplo. El MyType original sí lo implementa. Lo he agregado a continuación, modificado solo para poner el código hash en una variable temp antes de devolverlo.
Ejecutando a través del depurador, veo que las cinco invocaciones de GetHashCode devuelven un valor diferente. Y como MyType solo hereda de Object, es probable que este sea el mismo comportamiento que Object exhibiría.
¿Sería correcto concluir que el hash debería basarse en los contenidos de Value? Este fue mi primer intento de anular a los operadores, y en ese momento, no parecía que GetHashCode tuviera que ser particularmente elegante. (Esta es la primera vez que uno de mis cheques de igualdad no parecía funcionar correctamente.)
class Program
{
static void Main(string[] args)
{
int[] list = { 1, 3, 4, 4, 5 };
int[] list2 =
(from value in list
select value).Distinct().ToArray(); // One copy of each value.
MyType[] distinct =
(from value in list
select new MyType(value)).Distinct().ToArray(); // Two objects created with 4.
Array.ForEach(distinct, value => Console.WriteLine(value));
}
}
class MyType
{
public int Value { get; private set; }
public MyType(int arg)
{
Value = arg;
}
public override int GetHashCode()
{
int retval = base.GetHashCode();
return retval;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
MyType rhs = obj as MyType;
if ((Object)rhs == null)
return false;
return this == rhs;
}
public static bool operator ==(MyType lhs, MyType rhs)
{
bool result;
if ((Object)lhs != null && (Object)rhs != null)
result = lhs.Value == rhs.Value;
else
result = (Object)lhs == (Object)rhs;
return result;
}
public static bool operator !=(MyType lhs, MyType rhs)
{
return !(lhs == rhs);
}
}
¿Ha implementado GetHashCode()? Parece que podría devolver Value.HashCode() – cordialgerm
Está implementando esencialmente un tipo de valor en su tipo de referencia MyClass. No hay nada de malo en eso, pero debe pensar en términos del valor de MyClass como la identidad de la instancia en lugar de que la ubicación del objeto en la memoria sea su identidad (la predeterminada para los tipos de referencia). Por lo tanto, anule GetHashCode() para devolver Value.GetHashCode() para reflejar esa identidad. – dthorpe
@dthorpe - Creo que mi principal problema fue no haber reconocido cómo GetHashCode probablemente se implementaría en Object. Mi pensamiento en ese momento era esencialmente: "No necesito nada sofisticado, la implementación predeterminada debería ser lo suficientemente buena". No cometeré ese error otra vez. La próxima vez que vaya a anular el operador ==, encontraré una forma completamente diferente de arruinarlo. – ThatBlairGuy