Вам необходимо сделать переопределение thing
типа Equals
и GetHashCode
, чтобы указать его семантику равенства:
public sealed class Thing : IEquatable<Thing>
{
public int Id{get;set;}
public decimal ShouldMatch1 {get;set;}
public int OtherMatch2{get;set;}
public string DoesntMatter{get;set;}
public int SomeOtherDoesntMatter{get;set;}
public override int GetHashCode()
{
int hash = 17;
hash = hash * 31 + ShouldMatch1.GetHashCode() ;
hash = hash * 31 + OtherMatch2.GetHashCode() ;
return hash;
}
public override bool Equals(object other) {
return Equals(other as Thing);
}
public bool Equals(Thing other) {
if (other == null) {
return false;
}
return ShouldMatch1 == other.ShouldMatch1 &&
OtherMatch2 == other.OtherMatch2;
}
}
Обратите внимание, что запечатывание класса упрощает проверку на равенство. Также обратите внимание, что если вы поместите один из них в словарь в качестве ключа, но затем измените Id, ShouldMatch1 или OtherMatch2, вы не сможете найти его снова ...
Теперь, если вы используете настоящий анонимный тип, вам не удастся это сделать ... и сложно реализовать IEqualityComparer<T>
для передачи Intersect
, когда он анонимный. Вы можете написать метод IntersectBy
, немного похожий на метод DisinctBy
от MoreLINQ ... это, вероятно, самый чистый подход, если вы действительно используете анонимный тип.
Вы бы использовали это так:
var query = first.Intersect(second);
Затем вы получите IEnumerable<Thing>
, из которого вы сможете получить нужные биты.
Другой вариант - использовать объединение:
var query = from left in first
join right in second
on new { left.ShouldMatch1, left.OtherMatch2 } equals
new { right.ShouldMatch1, right.OtherMatch2 }
select new { left, right };
(РЕДАКТИРОВАТЬ: Я только что заметил, что другие тоже сделали объединение ... ну хорошо.)
Все же другой вариант , если вас интересуют только биты совпадения, - это проецирование последовательностей:
var query = first.Select(x => new { x.ShouldMatch1, x.OtherMatch2 })
.Intersect(second.Select(x => new { x.ShouldMatch1,
x.OtherMatch2 }));