Сравнение двух объектов - PullRequest
1 голос
/ 03 марта 2011

Использование Object.Equals приводит к значению false с двумя вновь созданными объектами, использующими один и тот же конструктор. Почему это? Я хочу иметь возможность сравнивать два объекта и видеть, являются ли они одинаковыми, другими словами, я хочу сделать тот же тест, что и выше, но я хочу иметь возможность получить истинное значение в первом тесте (так как два объекта должно быть идентично).

Как мне это сделать, не создав собственный метод сравнения для какого-либо конкретного класса.

using System;
class Program
{
    static void Main(string[] args)
    {
        Object Obj1 = new Object();
        Object Obj2 = new Object();
        Console.WriteLine(Obj1.Equals(Obj2));
        Obj2 = Obj1;
        Console.WriteLine(Obj1.Equals(Obj2)); 
    }
}

/* This example produces the following output:
False
True
 */

Добавление:

Object o1 = new Object();
Object o2 = new Object();

o1.value1 = 1;
o2.value1 = 1;

//Now I want to compare o1 and o2 and see if they are equal
//Can I do this without building my own function?

Ответы [ 8 ]

5 голосов
/ 03 марта 2011

Object.Equals() использует равенство ссылок для сравнения, которое будет иметь значение true, только если это та же ссылка на объект. Вы можете переопределить это поведение для своих собственных типов, производных от Object.

Из MSDN:

Реализация по умолчанию Equals поддерживает ссылочное равенство для ссылочные типы и битовое равенство для типов значений. Справочное равенство означает ссылки на объекты, которые по сравнению относятся к одному и тому же объекту. Побитовое равенство означает объекты сравниваемые имеют одинаковые двоичные представление.

Обратите внимание, что производный тип может переопределить метод Equals для реализовать равенство ценностей. Значение равенство означает сравниваемые объекты имеют одинаковое значение, даже если они имеют разные двоичные представления. Например, рассмотрим два десятичных объекты, которые представляют числа 1.10 и 1.1000. Десятичные объекты не имеют побитового равенства, потому что у них разные бинарные представления для учета различное количество конечных нулей. Тем не менее, объекты имеют значение равенство, потому что числа 1,10 и 1.1000 считаются равными для целей сравнения, так как трейлинг нули незначительны.

3 голосов
/ 03 марта 2011

Я спешил, когда сделал этот ответ, поэтому я переписал свой ответ.

Метод equals проверяет, равны ли ссылки на два объекта. Когда вы дважды создаете один и тот же класс с одними и теми же данными, они все еще хранятся в разных позициях в памяти, поэтому их ссылка не равна, и метод Equals возвращает false.

Чтобы проверять всякий раз, когда значение классов равно, вам нужно переопределить метод Equals, а также использовать операторы == и! =, Нам нужно их перегрузить.

Например, строковый класс переопределяет его, если он этого не сделает, будет напечатано false:

string test = "string";
string test2 = "string";
Console.WriteLine(test == test2);

Примеры:

// Example 1:
// Without overriding the Equals method:
Foo f1 = new Foo();
Foo f2 = new Foo();
f1.Name = "String";
f2.Name = "String";
bool fooEquals = f1 == f2; // False
f2.Name = "Test";
fooEquals f1 == f2; // False

// Example 2:
// With overriding the Equals method:
Foo f1 = new Foo();
Foo f2 = new Foo();
f1.Name = "String";
f2.Name = "String";
bool fooEquals = f1 == f2; // True
f2.Name = "Test";
fooEquals f1 == f2; // False

Это Foo в первом примере:

public class Foo
{
    public string Name { get; set; }
}

Это Foo во втором примере:

public class Foo
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        Foo p = obj as Foo;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (Name == p.Name);
    }

    public bool Equals(Foo p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (Name == p.Name);
    }

    public static bool operator ==(Foo f1, Foo f2)
    {
        return f1.Equals(f2);
    }

    public static bool operator !=(Foo f1, Foo f2)
    {
        return !f1.Equals(f2);
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

ПРИМЕЧАНИЕ: При переопределении Equals или перегрузке == /! = Visual Studio хочет переопределить функцию GetHashCode. Эта функция должна быть уникальной для каждого экземпляра Foo с одинаковыми значениями.

1 голос
/ 03 марта 2011

Большинство ответов верны, я просто приведу немного подробнее:

Любой экземпляр класса, производный от System.Object, за исключением тех, которые являются классами System.ValueType, является "Ссылка "класс.«Ссылочный» класс состоит из двух частей;«мясо» экземпляра помещается в память программы, называется «куча», а затем «стек» или «указатель» на этот адрес памяти помещается в стек.Для получения дополнительной информации о том, что такое стек и куча, и почему они необходимы, обратитесь к документации MSDN или основам компьютерного программирования.

В .NET - сравнение по умолчанию равенства двух переменных в ссылкеТип для сравнения адресов памяти, хранящихся в переменных.Это «эталонное равенство»;если две переменные указывают на один и тот же адрес памяти, они равны.Если нет, то это не так.

Для "семантического" или "структурного" равенства требуется более глубокий взгляд на то, что живет в пространстве памяти каждой переменной.Это не может быть сделано в общем случае;Разработчик должен определить для каждого класса, который он хочет сравнить, что делает два экземпляра его класса семантически равными.Это достигается путем переопределения метода Equals (), который унаследован от класса Object (и, следовательно, является общим для всех классов .NET).Переопределение Equals обычно имеет следующую структуру:

public override bool Equals (object other)
{
    //Reference equality is still a simple and necessary check
    if(Object.ReferenceEquals(this, other)) return true;

    //Another simple check; the two objects should be the same type
    if(this.GetType() != other.GetType()) return false;

    //Now, compare members of the object that you want to use to determine
    //"semantic" equality. These members, if also reference types, must also
    //be "semantically" equal.

    if(this.Property1 == other.Property1 && this.FieldA == other.FieldA && ... )
       return true;

    return false;
}

Реализация интерфейсов IComparable, IEquatable и IStructuralEquatable дает подсказки потребителям о том, что автор текущего класса имеет пользовательское определение равенства или другого сравнения.Они необходимы в некоторых случаях, а не во всех.

0 голосов
/ 03 марта 2011

Метод equals для класса объекта сравнивает две ссылки. Поскольку вы создаете новый объект, они никогда не будут равны.

0 голосов
/ 03 марта 2011

Тип object не имеет абсолютно никаких отличительных характеристик, кроме эталонной идентичности.Если вы хотите, чтобы два разных object экземпляра сравнивались одинаково, просто реализуйте свой собственный компаратор :

class ObjectComparer : IEqualityComparer<object>
{
    public bool Equals(object x, object y)
    {
        if (x == null || y == null)
        {
            return false;
        }

        return x.GetType == typeof(object) && y.GetType() == typeof(object);
    }

    public int GetHashCode(object obj)
    {
        if (obj == null)
        {
            return 0;
        }

        if (obj.GetType() == typeof(object))
        {
            return 1; // I don't know, whatever.
        }

        return obj.GetHashCode();
    }
}

Ой, подождите, это то, чего вы не хотитесделать.Ну, тогда создайте свой собственный тип, который будет вести себя так, как вы хотите:

sealed class SimpleObject()
{
    // No characteristics, all instances equal.
    public override bool Equals(object obj)
    {
        return obj is SimpleObject;
    }

    public override int GetHashCode()
    {
        return 0;
    }
}

Вы не можете просто изменить сам тип object.

0 голосов
/ 03 марта 2011

Объекты сравниваются с использованием ссылки на объект, в отличие от примитивов, которые сравниваются по значению. Это часто изводит новичков строками, которые во многих языках являются объектами, и они просто пытаются проверить свое равенство, используя примитивное сравнение.

Если вы действительно хотите иметь возможность сравнивать с помощью оператора ==, тогда вы можете перегрузить оператор .

0 голосов
/ 03 марта 2011

Object.Equals () является ссылочным равенством. Вы должны создать свой собственный метод сравнения, будь то переопределение equals, реализация IEqualityComparer или любой другой интерфейс сравнения.

0 голосов
/ 03 марта 2011

Я считаю, что вам нужно создать свой собственный метод сравнения и реализовать интерфейс ICompare

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...