2017-08-05 15 views
0

我發現一個有趣的事情,以此爲C#程序:如果你複製我的代碼和運行,一個空指針異常將被拋出「Equals」不能在超載操作函數中調用?

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

。爲什麼? PS:如果我在重載操作符+中使用「return s1.ID == s2.ID & & s1.Name == s2.Name」,那可以。

爲什麼?我正在使用net4.0 VS2015。

如果您通過將調試點放在「bool isSame =(s1 == s2);」你會很快發現它進入「==」重載函數3次,最後,s1和s2都是null!

+0

相反STU的'== null'使用'object.ReferenceEquals(STU,空)' –

+0

@IanMercer:但是,爲什麼運營商函數被調用調試3次?最後,s1 = s2 = null? – xqMogvKW

回答

2

儘管伊恩的評論將解決上述問題,但它不會最終解決一般問題。 問題的根源在於比較運算符的重載。

程序員期望null == myobject以及myobject == null是一個有效的表達式(正如您在執行.Equals時所做的那樣)。這對於上述類不起作用,因爲調用operator ==中的成員函數s1.Equals

因此,比較運算符的任何合理超載應該能夠處理真正的任何輸入而不會引發異常。毫無疑問,只需返回假。 這包括空值以及尚未分配所有屬性的類實例。

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

理由:

  • ReferenceEquals(s1, s2)處理null == null以及x == x。後者不需要比較內容。
  • s1 != null句柄null == x
  • x == null已由.Equals實施處理。

順便說一句:建議通過實施IEquatable<Student>重載相等運算符時提供一個強類型.Equals實施。

此外,您不應該使用.Equals來比較組件,因爲如果Name尚未分配到目前爲止,會由於類似原因而令人遺憾地失敗。

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

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

見尤瓦Itzchakov也將回答問題Operator overloading ==, !=, Equals

+1

它是'IEquatable '。沒有這樣的接口'IEqualityComparable '(雖然* *是* IEqualityComparer '但它的目的有點不同) – pinkfloydx33