比较两个对象

时间:2011-03-03 17:00:21

标签: c# object

使用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 个答案:

答案 0 :(得分:5)

Object.Equals()正在使用引用相等进行比较,如果它是相同的对象引用,则只会产生true。您可以为从Object派生的您自己的类型覆盖此行为。

来自MSDN:

  

Equals的默认实现   支持引用相等   引用类型和按位相等   对于价值类型。参考平等   表示对象引用   比较指的是同一个对象。   按位相等意味着对象   被比较的具有相同的二进制   表示。

     

请注意,派生类型可能   将Equals方法重写为   实现价值平等。值   平等意味着比较的对象   即使它们具有相同的价值   有不同的二进制表示。   例如,考虑两个Decimal   表示数字的对象   1.10和1.1000。 Decimal对象没有按位相等,因为   他们有不同的二进制   代表说明   不同数量的尾随零。   但是,对象具有价值   平等因为数字1.10和   自结尾以来,1.1000被认为是相同的比较目的   零是微不足道的。

答案 1 :(得分:3)

当我做出这个答案时,我很着急,这就是为什么我重写了我的答案。

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();
    }
}

注意:当重写等于或重载== /!=时,Visual Studio希望您覆盖GetHashCode函数。对于每个Foo实例,该函数应该是唯一的,具有相同的值。

答案 2 :(得分:1)

大多数答案都是正确的,我只是给出更多细节:

派生自System.Object的类的任何实例(System.ValueType类除外)都是“引用”类。 “参考”课程分为两部分;实例的“肉”放在程序的内存中,称为“堆”,然后将该内存地址的“引用”或“指针”放在堆栈中。有关堆栈和堆是什么以及为什么需要它们的更多信息,请参阅MSDN文档或计算机编程的基础入门。

在.NET中,引用类型的两个变量的相等性的默认比较是比较变量存储的内存地址。这是“参考平等”;如果两个变量指向相同的内存地址,则它们是相等的。如果没有,他们就不是。

对于“语义”或“结构”平等,需要更深入地了解每个变量的内存空间中的内容。在一般情况下不能这样做;开发人员必须为他希望比较的每个类定义是什么使他的类的两个实例在语义上相等。这是通过重写从Object类继承的Equals()方法来实现的(因此对所有.NET类都是通用的)。等于覆盖通常具有以下结构:

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接口为消费者提供了线索,即当前类的作者具有相等或其他比较的自定义定义。在某些情况下,它们是必要的,而不是全部。

答案 3 :(得分:0)

我相信你必须创建自己的比较方法,并实现ICompare接口

答案 4 :(得分:0)

Object.Equals()是引用相等。您必须构建自己的比较方法,无论是重写equals,还是实现IEqualityComparer,或任何其他比较接口。

答案 5 :(得分:0)

使用对象的引用来比较对象,而不像通过值进行比较的基元。这经常困扰带有字符串的新手,在很多语言中都是对象,他们只是尝试使用原始比较来检查它们的相等性。

如果您真的希望能够使用==运算符进行比较,那么您可以overload the operator

答案 6 :(得分:0)

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类型本身。

答案 7 :(得分:0)

对象类的equals方法比较两个引用。由于您正在创建一个新对象,因此它们永远不会相等。