Сравнение двух пользовательских объектов (с использованием IEqualityComparer)

Во-первых, я скажу, что я хочу сравнить следующее: Мой пользовательский объект (элемент) имеет список строк taxids. Я хочу посмотреть, встречаются ли все строки в одном списке в другом списке строк (также будет еще один taxids другого объекта (элемента).

Итак, это класс:

public class Item
{
    public long taxid { get; set; }
    public long contentid { get; set; }
    public string taxname { get; set; }
    public IEnumerable<string> taxids { get; set; }
}

Тогда это фиктивные пользовательские объекты:

    List<string> numbers = new List<string> { "5", "1" };
    List<string> numbers2 = new List<string> { "1", "2", "5","3","564" };

    Item pr = new Item();
    pr.contentid = 2517;
    pr.taxid = 2246;
    pr.taxids = numbers.AsEnumerable();
    pr.taxname = "nameItem1";
    List<Item> te = new List<Item>();
    te.Add(pr);
    IQueryable<Item> er = te.AsQueryable();

    Item pr2 = new Item();
    pr2.contentid = 0;
    pr2.taxid = 0;
    pr2.taxids = numbers2.AsEnumerable();
    pr2.taxname = "nameItem2";
    List<Item> te2 = new List<Item>();
    te2.Add(pr2);
    IQueryable<Item> er2 = te2.AsQueryable();

    IQueryable<Item> both = er.Intersect(er2, new ItemComparer());

Здесь я использую пользовательский компаратор ItemComparer. Вот код для этого:

public class ItemComparer : IEqualityComparer<Item>
{
    // items are equal if their names and item numbers are equal.
    public bool Equals(Item x, Item y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the items' properties are equal.
        return x.taxids.Intersect(y.taxids).SequenceEqual(x.taxids);
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public int GetHashCode(Item item)
    {
        //Check whether the object is null
        if (Object.ReferenceEquals(item, null)) return 0;

        //Get hash code for the Name field if it is not null.
        int hashItemName = item.taxids == null ? 0 : item.taxids.GetHashCode();

        //Calculate the hash code for the item.
        return item.taxids.GetHashCode();

        //return "a".GetHashCode();
    }
}

Проблема в том, что переменная both ничего не имеет в поле Taxids, обычно у меня должен быть список "5" "1".

Я знаю, что hashCode должен быть одинаковым при сравнении. но taxids никогда не будет прежним. Потому что мы ищем строки в другом списке строк.

Кто-нибудь может еще помочь мне с этой проблемой?

(Также небольшой вопрос: если я всегда возвращаю один и тот же хэш-код для всего, например "a".GetHashCode() =>, должно ли это работать или нет?

заранее спасибо


person Ozkan    schedule 19.12.2011    source источник


Ответы (2)


Я думаю, ваша проблема в том, что у вас нет двунаправленного равенства. в зависимости от того, с какой стороны находится ваш объект, pr и pr 2 не равны.

Я не уверен, есть ли гарантия, какой объект является x, а какой y в вашем компараторе. Что, если pr2 окажется x в вашем компараторе?

что касается хэш-кода, вы делаете taxids.GetHashCode() - это просто список, а не имя, и ничего вам не скажет о равенстве.

person flq    schedule 19.12.2011

return x.taxids.Intersect(y.taxids).SequenceEqual(x.taxids);

Ваше сравнение равенства в настоящее время не учитывает различный порядок элементов в коллекциях. В качестве грубого обходного пути вы можете заказать их перед сравнением или лучше добавить элементы в хэш-набор:

return x.taxids.Intersect(y.taxids)
               .OrderBy(x => x)
               .SequenceEqual(x.taxids.OrderBy(x => x));

Также вы должны предоставить соответствующую реализацию GetHashCode(), реализация по умолчанию не зависит от фактических элементов в списке, поэтому не будет получен один и тот же хэш-код для двух разных экземпляров Item, которые имеют одни и те же элементы в коллекции. Более подходящую реализацию для вашего случая можно найти в этот другой пост SO< /а>.

person BrokenGlass    schedule 19.12.2011
comment
При выполнении пересечения он всегда возвращается в одном и том же порядке. Но спасибо за информацию - person Ozkan; 19.12.2011
comment
Он вернет элементы в том порядке, в котором они были собраны (и даже на которые не стоит полагаться) — в одной из коллекций. Это не обязательно то же самое, что и элементы в другой коллекции, поэтому необходимо изменить порядок. - person BrokenGlass; 19.12.2011
comment
Спасибо за информацию. И для метода getHashcode. Может быть, вы знаете больше, чем я. Могу ли я всегда использовать один и тот же хэш-код для всего? Например: "a".GetHashCode(). Потому что у меня никогда не будет двух одинаковых списков. В указанном вами URL-адресе списки можно сделать одинаковыми, сделав их разными, но у меня в списке совершенно разные элементы. - person Ozkan; 19.12.2011