0

I found an interesting thing, take this as a C# program:

namespace ConsoleApplication1
{
    using System;

    public class Student
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public override bool Equals(object comparedStudent)
        {
            Student stu = comparedStudent as Student;

            if (stu == null)
            {
                return false;
            }
            return ID.Equals(stu.ID) && Name.Equals(stu.Name);
        }

        public override int GetHashCode()
        {
            return ID.GetHashCode() ^ Name.GetHashCode();
        }
        /// <summary>
        /// Notice that this will cause NullPointException……Why?
        /// If I use "return s1.ID==s2.ID && s1.Name==s2.Name", that'd be OK.
        /// </summary>
        public static bool operator ==(Student s1, Student s2)
        {
            return s1.Equals(s2);
        }

        public static bool operator !=(Student s1, Student s2)
        {
            return !s1.Equals(s2);
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            Student s1 = new Student();
            s1.ID = 1;
            s1.Name = "YourName";
            Student s2 = new Student();
            s2.ID = 1;
            s2.Name = "YourName";

            //Why there's an exception here (NullPoint exception)
            bool isSame = (s1 == s2);
            Console.WriteLine(isSame);
        }
    }
}

If you copy my codes and run, a NullPointer exception will be thrown out. Why?

PS:If I use "return s1.ID==s2.ID && s1.Name==s2.Name" in the overload operator +, that'd be OK.

Why? I'm using net4.0 VS2015.

And if you debug by dropping the debug point at "bool isSame = (s1 == s2);" You'll soon find it enters into the "==" overload function 3 times, and in the end, s1 and s2 are null!

Marcel
  • 1,688
  • 1
  • 14
  • 25
xqMogvKW
  • 628
  • 7
  • 17

1 Answers1

2

Although Ians comment will fix the above issue it will not finally fix the problem in general. The origin of the problem is in the overload of the comparison operators.

A programmer expects null == myobject as well as myobject == null to be a valid expression (as you did as well in implementation of .Equals). This does not work for the above class because of the invocation of the member function s1.Equals in operator ==.

So any reasonable overload of a comparison operator should be able to handle really any input without throwing an exception. In doubt simply return false. This includes null values as well as class instances that do not yet have all properties assigned.

public static bool operator ==(Student s1, Student s2) =>
  ReferenceEquals(s1, s2) || (!ReferenceEquals(s1, null) && s1.Equals(s2));

Rationale:

  • ReferenceEquals(s1, s2) handles null == null as well as x == x. The latter does not require to compare the content.
  • s1 != null handles null == x.
  • x == null is already handled by the .Equals implementation.

By the way: it is recommended to provide a strongly typed .Equals implementation when overloading equality operators by implementing IEquatable<Student>.

Furthermore you should not use .Equals to compare components, because this will sadly fail for a similar reason if Name has not been assigned so far.

public override bool Equals(object obj) =>
  Equals(obj as Student);

public bool Equals(Student stu) =>
  !ReferenceEquals(stu, null) && ID == stu.ID && Name == stu.Name;

See also the reply of Yuval Itzchakov to question Operator overloading ==, !=, Equals

Marcel
  • 1,688
  • 1
  • 14
  • 25
  • 1
    It's `IEquatable`. There's no such interface `IEqualityComparable` (though there *is* an `IEqualityComparer` but it's purpose is somewhat different) – pinkfloydx33 Aug 05 '17 at 11:26