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 - порядок агностики, тому не має значення, чи списки сортуються по-різному. Важливо лише те, що вони не містять нічого, крім рівнозначних членів.
Зауважте: дивна назва означає те, що метод не враховує порядок елементів у списку. Якщо ви дбаєте про порядок елементів у списку, цей спосіб не для вас!