参考类型的平等

时间:2013-08-14 16:06:58

标签: c#

我对引用类型中的内容相等性有点困惑。在任何一种情况下,我都不会压倒平等 - 所以为什么行为会有所不同。

参见2个简单的代码示例:

示例1:返回True

class Program
{
    static void Main(string[] args)
    {
        object o1 = "ABC";
        object o2 = "ABC";

        Console.WriteLine("object1 and object2: {0}", o1.Equals(o2));
    }
}

示例2:两个语句都返回False

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person("John");
        Person person2 = new Person("John");

        Console.WriteLine("person1 and person2: {0}", person1.Equals(person2));
        Console.WriteLine("person1 and person2: {0}", ((object)person1).Equals((object)person2));

        Console.ReadLine();
    }
}

public class Person
{
    private string personName;

    public Person(string name)
    {
        this.personName = name;
    }
}

7 个答案:

答案 0 :(得分:8)

这里有两种效果:

  • 字符串实习意味着实际即使您执行引用相等性检查,您仍会看到True。你可以这样解决:

    object o1 = new StringBuilder("ABC").ToString();
    object o2 = new StringBuilder("ABC").ToString();
    
  • System.String overrides the Equals method来比较字符串的内容

      

    此方法执行序数(区分大小写和区分大小写)比较。

    你可以在这里看到不同之处:

    object o1 = new StringBuilder("ABC").ToString();
    object o2 = new StringBuilder("ABC").ToString();
    Console.WriteLine(o1.Equals(o2)); // Prints True due to overriding
    Console.WriteLine(ReferenceEquals(o1, o2)); // Prints False
    

您的班级不会覆盖Equals,因此您将获得default implementation in Object,即比较参考资料:

  

如果当前实例是引用类型,则Equals(Object)方法测试引用相等性,并且对Equals(Object)方法的调用等同于对ReferenceEquals方法的调用。

您可以通过覆盖Equals

来合理地轻松解决问题
// It's easier to implement equality correctly on sealed classes
public sealed class Person
{
    private readonly string personName;

    public Person(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }
        this.personName = name;
    }

    public override bool Equals(object other)
    {
        Person person = other as Person;
        return person != null && person.personName.Equals(personName);
    }

    // Must override GetHashCode at the same time...
    public override int GetHashCode()
    {
        // Just delegate to the name here - it's the only thing we're
        // using in the equality check
        return personName.GetHashCode();
    }
}

请注意,在我们可以使用的Equals实现中:

return person != null && person.personName == personName;

...因为string 重载了==运算符。但那是另一回事:)

答案 1 :(得分:3)

示例1返回true,因为Equals正在比较这些值,因为该对象被视为字符串;而示例2是比较对象的实例,因为它们各自指向不同的内存块,它们不相等。

答案 2 :(得分:2)

默认情况下,参考类型的引用Equals默认为ReferenceEquals。您必须使用Person的实例,因此它会返回false

String会覆盖Equals以实现值语义。因此,如果使用string将两个单独的Equals实例与相同的值进行比较,则返回true。

感谢字符串实习,"ABC"指向同一个实例。因此,即使ReferenceEquals在第一个示例中也会返回true

编译时类型与Equals无关,因为它是一个虚方法。所以你的演员object没有效果。转换为对象只会影响==!=,因为它们已经过载,而不会被覆盖。

答案 3 :(得分:1)

重写字符串上的equals运算符以逐字节比较字符串。在第二个示例中,您将比较实例,即内存地址,这两个实例对于Person()的两个实例是不同的

答案 4 :(得分:0)

在第一种情况下,String.Equals会覆盖Object.Equals,并检查实际的字符串值。未使用引用相等性。在第二种情况下,正在使用默认引用相等。

但是,如果您使用object.ReferenceEquals,则由于string interning会导致相同的行为,这会导致前两个对象指向内存中的相同字符串(相同的引用),因为你正在使用字符串文字。

答案 5 :(得分:0)

String已覆盖其Equals方法,因此如果两个字符串在同一顺序中包含完全相同的字符,则它们为Equal。你的Person没有这样的覆盖,所以从对象继承,使用引用等于它是相等的仲裁者。

答案 6 :(得分:0)

由于.net中的字符串实习,字符串引用相等(你会对它进行谷歌搜索)