using System.Collections.Generic;
using System.Linq;
namespace YourProject.Extensions
{
public static class ListExtensions
{
public static bool SetwiseEquivalentTo<T>(this List<T> list, List<T> other)
where T: IEquatable<T>
{
if (list.Except(other).Any())
return false;
if (other.Except(list).Any())
return false;
return true;
}
}
}
Czasami musisz tylko wiedzieć, czy dwie listy są różne, a nie jakie są te różnice. W takim przypadku rozważ dodanie tej metody rozszerzenia do swojego projektu. Zauważ, że wymienione obiekty powinny implementować IEquatable!
Stosowanie:
public sealed class Car : IEquatable<Car>
{
public Price Price { get; }
public List<Component> Components { get; }
...
public override bool Equals(object obj)
=> obj is Car other && Equals(other);
public bool Equals(Car other)
=> Price == other.Price
&& Components.SetwiseEquivalentTo(other.Components);
public override int GetHashCode()
=> Components.Aggregate(
Price.GetHashCode(),
(code, next) => code ^ next.GetHashCode()); // Bitwise XOR
}
Niezależnie od Component
klasy, przedstawione tutaj metody Car
powinny być implementowane prawie identycznie.
Bardzo ważne jest, aby zauważyć, jak napisaliśmy GetHashCode. W celu prawidłowego wdrożenia IEquatable
, Equals
i GetHashCode
moszczu działać na właściwości instancji w logicznie zgodny sposób.
Dwie listy o tej samej zawartości są wciąż różnymi obiektami i będą generować różne kody skrótu. Ponieważ chcemy, aby te dwie listy były traktowane jako równe, musimy pozwolić na GetHashCode
wygenerowanie tej samej wartości dla każdej z nich. Możemy to osiągnąć, delegując kod skrótu do każdego elementu na liście i używając standardowego bitowego XOR, aby połączyć je wszystkie. XOR jest niezależny od kolejności, więc nie ma znaczenia, czy listy są sortowane inaczej. Liczy się tylko to, że zawierają tylko równoważnych członków.
Uwaga: dziwna nazwa ma sugerować fakt, że metoda nie uwzględnia kolejności elementów na liście. Jeśli zależy Ci na kolejności elementów na liście, ta metoda nie jest dla Ciebie!