c#, Как найти, равны ли два объекта

Я должен знать лучший способ сравнить два объекта и узнать, равняются ли там. Я являюсь переопределяющим и GethashCode и Равняюсь. Таким образом, основной класс похож:

public class Test
{
    public int Value { get; set; }
    public string String1 { get; set; }
    public string String2 { get; set; }

    public override int GetHashCode()
    {
        return Value ^ String1.GetHashCode() ^ String2.GetHashCode();
    }

    public override bool Equals( object obj )
    {
        return GetHashCode() == obj.GetHashCode();
    }
}

Так для тестирования я создал два объекта:

Test t = new Test()
{
    Value = 1,
    String1 ="One",
    String2 = "One"
};

Test t2 = new Test()
{
    Value = 1,
    String1 = "Two",
    String2 = "Two"
};

bool areEqual = t.Equals( t2 );

В тестировании этого areEqual возвращает истинное событие, хотя оба объекта отличаются. Я понимаю, что это вызвано тем, что String1 и String2 являются тем же значением в каждом объекте, и таким образом уравновешивает друг друга при хешировании.

Существует ли лучший путь от хеширования объекта, что метод, который я имею, который решит мой вопрос?

30
задан lancscoder 27 May 2010 в 10:46
поделиться

4 ответа

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

public override bool Equals(object obj)
{
    Test test = obj as Test;
    if (obj == null)
    {
        return false;
    }
    return Value == test.Value &&
        String1 == test.String1 &&
        String2 == test.String2;
}

Несколько замечаний:

  • Ваш способ создания хэш-кода даст то же значение для любого фиксированного значения if Строка1 и Строка2 одинаковы; он также сработает, если String1 или String2 имеет значение NULL. Это неудачный аспект использования XOR для хеширования. Я предпочитаю что-то вроде этого:

     // Поместите этот метод расширения где-нибудь в служебный класс
    public static int SafeGetHashCode  (это значение T), где T: класс
    {
    возвращаемое значение == null? 0: значение.GetHashCode ();
    }
    
    // и это в вашем реальном классе
    публичное переопределение int GetHashCode ()
    {
    int hash = 19;
    хэш = хэш * 31 + значение;
    хэш = хэш * 31 + String1.SafeGetHashCode ();
    хеш = хеш * 31 + String2.SafeGetHashCode ();
    вернуть хеш;
    }
    
  • Вообще говоря, равенство становится сложной задачей, когда речь идет о наследовании. Вы можете подумать о том, чтобы запечатать свой класс.

  • Вы также можете реализовать IEquatable

40
ответ дан 27 November 2019 в 23:37
поделиться

Ваш Equals неверен - это должно определять , что это означает, что две вещи равны - и наличие одного и того же хэш-кода не означает равенство (однако; другой хеш-код действительно означает неравенство). Если «равенство» означает «обе строки попарно равны», тогда проверяет это.

Re лучший хеш; xor печально известен этим, поскольку тривиально получить 0 с помощью xor значение с самим собой. Лучшим подходом может быть что-то вроде:

int i = 0x65407627;
i = (i * -1521134295) + Value.GetHashCode();
i = (i * -1521134295) + (String1 == null ? 0 : String1.GetHashCode());
i = (i * -1521134295) + (String2 == null ? 0 : String2.GetHashCode());
return i;
16
ответ дан 27 November 2019 в 23:37
поделиться

Для любых двух объектов равенство объектов подразумевает равенство хэш-кода, однако равенство хэш-кода не означает равенства объектов. Из Object.GetHashCode в MSDN:

Хэш-функция должна иметь следующие свойства:

Если два объекта сравниваются как равные, GetHashCode для каждого объекта должен возвращать то же значение. Тем не мение, если два объекта не сравниваются как равно, методы GetHashCode для два объекта не должны возвращать разные значения.

Другими словами, ваше Equals написано неправильно. Это должно быть примерно так:

public override bool Equals(object obj)
{
    Test other = obj as Test;
    if (other == null)
        return false;

    return (Value == other.Value)
        && (String1 == other.String1)
        && (String2 == other.String2);
}

GetHashCode подходит для коллекций (например, Dictionary ), чтобы быстро определить приблизительное равенство. Equals используется для сравнения, если два объекта действительно одинаковы.

2
ответ дан 27 November 2019 в 23:37
поделиться

не будет ли функция Equals всегда проверять только на одинаковый тип, не должно ли быть:

//override
    public bool Equals(Test other)//(object obj) 
    {
        //return GetHashCode() == obj.GetHashCode();
        return (Value == other.Value) &&
               (String1 == other.String1) &&
               (String2 == other.String2);
    }

с уважением. Oops

0
ответ дан 27 November 2019 в 23:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: