Я столкнулся с некоторым странным поведением при использовании C # HastSet с методом LINQ Join, которое я не понимаю.Я упростил то, что я делаю, чтобы сосредоточиться на поведении, которое я вижу.
У меня есть следующее:
private HashSet<MyClass> _mySet; // module level
IEnumerable<ISearchKey> searchKeys; // parameter.
// Partial key searches are allowed.
private IEqualityComparer<ICoreKey> _coreKeyComparer; // Module level.
// Compares instances of MyClass and ISearchKey to determine
// if they match.
Учитывая, что
- Между searchKeys и _mySet существует отношение 1-ко-многим.
- MyClass реализует интерфейс IPartialKey и ICoreKey.
- ISearchKey наследуется от IPartialKey и ICoreKey.
- Экземпляр MyClass и ISearchKey оба переопределяют метод GetHashCode.
- Значение хеш-кода MyClass основано на его полном значении ключа, которое включает значения ICoreKey и IPartialKey и другие поля.
- Полные ключи, используемые MyClass, не являются уникальными.Два разных экземпляра MyClass могут иметь одинаковый хеш-код.
- Значение хеш-кода ISearchKey основано только на его значениях ICoreKey и IPartialKey.т.е. хеш-код ISearchKey может отличаться от хеш-кода для соответствующего экземпляра MyClass.(Примечание: в случае, когда я впервые столкнулся с проблемой, значения IPartialKey ISearchKey соответствуют полному ключу MyClass, поэтому методы GetHashCode возвращают одинаковое значение для ISearchKey и MyClass. Я включил дополнительную сложность, чтобы лучше проиллюстрировать основную логикуо том, что я делаю.)
- Метод _coreKeyComparer.GetHashCode возвращает одно и то же значение для соответствующих экземпляров ISearchKey и MyClass, используя только их значения ICoreKey.
- Метод _coreKeyComparer.Equals приводит параметры кMyClass и ISearchKey соответственно и возвращает true, если их значения IPartialKey совпадают.(Примечание: _coreKeyComparer был тяжело протестирован и работает правильно.)
Я ожидал, что объединение двух коллекций должно привести к чему-то вроде:
{searchKey_a, myClass_a1},
{searchKey_a, myClass_a2},
{searchKey_a, myClass_a3},
{searchKey_b, myClass_b1},
{searchKey_b, myClass_b2},
{searchKey_c, myClass_c1},
{searchKey_c, myClass_c2},
{searchKey_c, myClass_c3},
{searchKey_c, myClass_c4},
etc....
т.е. тот же ISearchKeyэкземпляр будет происходить несколько раз, по одному разу для каждого соответствующего экземпляра MyClass, к которому он присоединен.
Но когда я выполняю объединение с searchKeys на _mySet:
var matchedPairs = searchKeys
.Join(
_mySet,
searchKey => searchKey,
myClass => myClass,
(searchKey, myClass) => new {searchKey, myClass},
_coreKeyComparer)
.ToList();
, я получаю только один экземпляр MyClass наэкземпляр searchKeyClass.то есть коллекция matchedPairs выглядит следующим образом:
{searchKey_a, myClass_a1},
{searchKey_b, myClass_b1},
{searchKey_c, myClass_c1},
etc....
Однако если я переверну объединение, перейдем от _mySet к searchKeys:
var matchedPairs = _mySet
.Join(
searchKeys,
myClass => myClass,
searchKey => searchKey,
(myClass, searchKey) => new {searchKey, myClass},
_coreKeyComparer)
.ToList();
Я получу правильную коллекцию matchedPairs.Все соответствующие записи из _mySet возвращаются вместе с searchKey, с которым они сопоставлены.
Я проверил документацию и изучил несколько примеров и не вижу причин, по которым соединение searchKeys-to-_mySet дает неправильный ответ, а _mySet-to-searchKeys дает правильный / другой ответ.
(Примечание: я также пытался использовать GroupJoin из searchKeys в _myset и сравнивать результаты. То есть каждый экземпляр searchKeyClass нашел не более одного результата из _mySet.)
Либо я не понимаю, какПредполагается, что метод Join работает, или Join работает с HashSet иначе, чем с List или другим типом коллекции.
Если первое, мне нужно разъяснение, чтобы я не допустил ошибок при использовании Join в будущем.
Если второе, то это другое поведение - ошибка .Net, или этоправильное поведение с HashSet?
Предполагая, что поведение правильное, я был бы очень признателен, если бы кто-то объяснил основную логику этого (неожиданного) поведения Join / HashSet.
Просто чтобы прояснить, я уже исправил свой код, чтобы он возвращал правильные результаты, я просто хочу понять, почему я изначально получил неправильные результаты.