Сравнение двух пользовательских объектов (с использованием IEqualityComparer) - PullRequest
1 голос
/ 19 декабря 2011

Во-первых, я скажу, что я хочу сравнить следующее: Мой пользовательский объект (элемент) имеет список строк 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".

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 19 декабря 2011

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

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

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

0 голосов
/ 19 декабря 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 .

...