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;
}
}
}
Іноді потрібно лише знати, чи два списки різні, а не те, що ці відмінності. У такому випадку розгляньте можливість додавання цього методу розширення до свого проекту. Зауважте, що ваші перелічені об'єкти повинні реалізувати IEquatable!
Використання:
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
}
Незалежно від Component
класу, показані тут методи Car
повинні бути реалізовані майже однаково.
Дуже важливо відзначити, як ми написали GetHashCode. Для того, щоб належним чином реалізувати IEquatable
, Equals
і GetHashCode
треба працювати на властивості екземпляра в логічно сумісним способом.
Два списки з однаковим вмістом все ще є різними об'єктами, і вони створюватимуть різні хеш-коди. Оскільки ми хочемо, щоб ці два списки розглядалися як рівні, ми повинні дозволити GetHashCode
виробляти однакове значення для кожного з них. Ми можемо досягти цього, делегувавши хеш-код кожному елементу у списку, і використовувати стандартний побітовий XOR для об'єднання їх усіх. XOR - порядок агностики, тому не має значення, чи списки сортуються по-різному. Важливо лише те, що вони не містять нічого, крім рівнозначних членів.
Зауважте: дивна назва означає те, що метод не враховує порядок елементів у списку. Якщо ви дбаєте про порядок елементів у списку, цей спосіб не для вас!