2012-04-23 12 views
6

Tôi vẫn còn mới đối với các nhà khai thác quá tải. Tôi nghĩ rằng tôi đã làm một công việc tuyệt vời cho đến khi tôi nhấn vấn đề này. NullReferenceException được ném vào toán tử! =. Tôi giả sử nó sử dụng nó trong phương pháp CompareTo nhưng tôi không hoàn toàn chắc chắn. Nếu bất cứ ai có thể chỉ cho tôi đúng hướng tôi sẽ rất biết ơn.Làm thế nào để ghi đè đúng cách bình đẳng?

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace WindowsFormsApplication2 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      List<Task> tasks = new List<Task>(); 
      tasks.Add(new Task("first", DateTime.Now.AddHours(2))); 
      tasks.Add(new Task("second", DateTime.Now.AddHours(4))); 
      tasks.TrimExcess(); 
      tasks.Sort(); 
     } 
    } 
    public class Task : IComparable 
    { 
     public Task() 
     { 
     } 
     public Task(string nameIn, DateTime dueIn) 
     { 
      nameOfTask = nameIn; 
      dateDue = dueIn; 
     } 
     DateTime dateDue; 
     string nameOfTask; 

     public static bool operator <(Task t1, Task t2) 
     { 
      return (t1.dateDue < t2.dateDue); 
     } 
     public static bool operator >(Task t1, Task t2) 
     { 
      return (t1.dateDue > t2.dateDue); 
     } 
     public static bool operator ==(Task t1, Task t2) 
     { 
      return (t1.dateDue == t2.dateDue); 
     } 
     public static bool operator !=(Task t1, Task t2) 
     { 
       return (t1.dateDue != t2.dateDue); 

     } 
     public override int GetHashCode() 
     { 
      return Int32.Parse(this.dateDue.ToString("yyyymmddhhmmss")); 
     } 
     public override bool Equals(System.Object obj) 
     { 
      if (obj == null) return false;  

      Task t = obj as Task; 
      if ((System.Object)t == null) return false; 
      return (this.dateDue == t.dateDue); 
     } 
     int IComparable.CompareTo(object obj) 
     { 
      if (obj == null) return 1; 

      Task t = obj as Task; 
      if (t != null) 
      { 
       return this.dateDue.CompareTo(t.dateDue); 
      } 
      else 
       throw new ArgumentException("Object is not a Task"); 
     } 
    } 
} 

Khi tôi nhận xét các toán tử băm, chương trình hoạt động như dự định. Câu hỏi của tôi là làm thế nào tôi có thể bảo vệ các nhà khai thác nhị phân của tôi từ tài liệu tham khảo null để tôi có thể giữ chúng để so sánh thủ công? Cảm ơn bạn đã dành thời gian.

+1

Một trong các đối tượng 'Task' mà bạn đang so sánh với'! = 'Được đặt thành' null'. – dasblinkenlight

+1

Phải-o .. Bạn cần giả sử 't1' và/hoặc' t2' có thể là rỗng trong tất cả các hàm tĩnh đó. –

Trả lời

13

Cả hai câu trả lời được đưa ra đều sai. Câu trả lời được chấp nhận là sai vì nó vô tình đệ quy. Câu trả lời khác là sai bởi vì nó nói rằng null không bằng null.

Việc triển khai các toán tử của bạn đều sai; chúng được yêu cầu để xử lý chính xác các đầu vào rỗng.

Việc triển khai GetHashCode của bạn bị hỏng sâu; bạn cố gắng đặt một số có mười bốn chữ số vào một định dạng có thể chấp nhận chín chữ số. Đơn giản chỉ cần gọi GetHashCode vào ngày; không cần phải đi qua rigamarole này biến nó thành một chuỗi và sau đó biến nó thành một số!

Cách đúng để viết mã là sử dụng object.ReferenceEquals để so sánh tham chiếu thay vì sử dụng các toán tử ==!=; nó là quá dễ dàng để làm một đệ quy ngẫu nhiên.

Các mô hình điển hình đi như thế này:

public static bool operator ==(Task t1, Task t2)   
{ 
    if (object.ReferenceEquals(t1, t2)) return true; 
    // All right. We know that they are (1) not the same object, and 
    // (2) not both null. Maybe one of them is null. 
    if (object.ReferenceEquals(t1, null)) return false; 
    if (object.ReferenceEquals(t2, null)) return false; 
    // They are not the same object and both are not null. 
    return t1.dateDue == t2.dateDue; 
} 

public static bool operator !=(Task t1, Task t2)   
{ 
    // Simply call the == operator and invert it. 
    return !(t1 == t2); 
} 

public override bool Equals(object t) 
{ 
    return (t as Task) == this; 
} 

public override int GetHashCode() 
{ 
    return this.dateDue.GetHashCode(); 
} 

Các toán tử so sánh khác còn lại như một bài tập.

+0

+1 và cảm ơn bạn đã khắc phục! Tôi đoán tôi nên thử ngay cả những đoạn mã đơn giản nhất trong trình gỡ lỗi trước khi đăng ... – dasblinkenlight

+0

Tôi hiểu rồi! Cảm ơn bạn, điều này khắc phục rất nhiều. vấn đề của tôi là tôi đã sử dụng logic của tôi để kiểm tra so sánh thay vì cố gắng sử dụng object.ReferenceEquals. Cảm ơn sự kiên nhẫn và câu trả lời của bạn. – Powe8525

+0

Đối với biện pháp tốt, người ta cũng có thể thực hiện 'IEquatable '. Đó là quan trọng hơn cho valuetypes để tránh boxing, nhưng nó không làm tổn thương làm với các loại tài liệu tham khảo quá. – CodesInChaos

-4
public static bool operator !=(Task t1, Task t2) 
     { 
       if (null == t1 || null == t2) { return false;} 
       return (t1.dateDue != t2.dateDue); 

     } 
+3

Hmm, và nếu 't1' là null và' t2' không phải là rỗng, sẽ không bạn mong đợi điều này để trả về 'true'? –

+0

Đó là một ví dụ. Các op nên đủ thông minh để xác định logic của riêng mình. –

+0

Bạn cũng quên truyền 't1' /' t2' thành 'đối tượng' trước khi so sánh với' null'. Và rối tung lên trường hợp đặc biệt quan trọng của 'null == null' không được bào chữa bằng cách đơn giản nói đây là một ví dụ. – CodesInChaos

3

Dường như một trong những Task đối tượng mà bạn đang so sánh với != được thiết lập để null. Toán tử được tích hợp != so sánh các tham chiếu và không ngắt, nhưng toán tử của bạn cố gắng bỏ qua nhiệm vụ và ngắt.

public static bool operator !=(Task t1, Task t2) { 
    if (ReferenceEquals(t1, null)) { 
     return !ReferenceEquals(t2, null); // return true only if t2 is *not* null 
    } 
    if (ReferenceEquals(t2, null)) { 
     return true; // we know that t1 is not null 
    } 
    return (t1.dateDue != t2.dateDue); 
} 

thi này trả false khi cả hai nhiệm vụ là null. Bạn nên thực hiện kiểm tra null đối xứng trong toán tử ==.

+0

Cảm ơn bạn, tôi đã thử một cái gì đó như thế này chỉ để có được một ngăn xếp tràn, tôi thấy nơi tôi đã đi sai. Bạn có thể giải thích những gì Symmetric null kiểm tra là (google có vẻ bối rối về nó)? – Powe8525

+1

@ Powe8525 Khi tôi đề cập rằng hành vi của toán tử 'bool ==' của bạn cần phải đối xứng với toán tử 'bool operator! =', Tôi có nghĩa là nó sẽ xử lý hai giá trị 'null' bằng nhau và' null 'không được bằng với giá trị không null. Việc thực hiện '! =' Từ câu trả lời tuân theo các quy tắc này, do đó việc thực hiện '==' cũng nên tuân thủ chúng. – dasblinkenlight

+1

@ Powe8525: Bạn chính xác; mã được đưa ra ở đây bị hỏng vì nó tự gọi. Mã đúng là bắt đầu với 'if (object.ReferenceEquals (t1, null)) {return! Object.ReferenceEquals (t2, null); } ' –