Sto provando a scrivere una query Linq che restituisce una matrice di oggetti, con valori univoci nei relativi costruttori. Per i tipi interi, Distinct restituisce solo una copia di ciascun valore, ma quando provo a creare il mio elenco di oggetti, le cose vanno in pezzi. Sospetto che sia un problema con l'operatore di uguaglianza per la mia classe, ma quando imposto un breakpoint non viene mai colpito.Distinct() restituisce i duplicati con un tipo definito dall'utente
Il filtraggio del duplicato int in una sottoespressione risolve il problema, inoltre mi salva dalla creazione di oggetti che verranno immediatamente eliminati, ma sono curioso del perché questa versione non funzioni.
AGGIORNAMENTO: 11:04 PM Diverse persone hanno sottolineato che MyType non sovrascrive GetHashCode(). Temo di aver semplificato eccessivamente l'esempio. Il MyType originale lo implementa davvero. L'ho aggiunto di seguito, modificato solo per inserire il codice hash in una variabile temporanea prima di restituirlo.
Eseguendo il debugger, vedo che tutte e cinque le invocazioni di GetHashCode restituiscono un valore diverso. E poiché MyType eredita solo da Object, questo è presumibilmente lo stesso comportamento che l'oggetto mostrerebbe.
Sarei corretto quindi per concludere che l'hash dovrebbe invece essere basato sul contenuto di Valore? Questo è stato il mio primo tentativo di scavalcare gli operatori e, al momento, non sembrava che il codice GetHash fosse particolarmente elaborato. (Questa è la prima volta che uno dei miei assegni di uguaglianza non sembra funzionare correttamente.)
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);
}
}
Avete implementato GetHashCode()? Sembra che tu possa restituire Value.HashCode() – cordialgerm
Stai essenzialmente implementando un tipo di valore nel tuo tipo di riferimento MyClass. Non c'è niente di sbagliato in questo, ma è necessario pensare in termini del valore di MyClass come identità dell'istanza anziché della posizione dell'oggetto in memoria che è la sua identità (l'impostazione predefinita per i tipi di riferimento). Quindi, eseguire l'override di GetHashCode() per restituire Value.GetHashCode() per riflettere tale identità. – dthorpe
@dthorpe - Penso che il mio problema principale fosse un errore nel riconoscere come probabilmente GetHashCode fosse implementato in Object. All'epoca pensavo essenzialmente: "Non ho bisogno di niente di particolare, l'implementazione di default dovrebbe essere abbastanza buona". Non farò di nuovo quell'errore La prossima volta che andrò a sostituire l'operatore ==, troverò un modo completamente diverso di rovinarlo. – ThatBlairGuy