2010-07-07 26 views
37

Trong khi học .net (bởi C#) tôi tìm thấy 5 cách để kiểm tra sự bình đẳng giữa các đối tượng.5 cách để kiểm tra bình đẳng .net .. tại sao? và sử dụng cái gì?

  1. Phương thức ReferenceEquals().
  2. Phương thức equals() ảo. (System.Object)
  3. Phương thức static Equals().
  4. Phương thức Bằng từ giao diện IEquatable.
  5. Toán tử so sánh ==.

Câu hỏi của tôi là:

  1. Tại sao có rất nhiều Equals() phương pháp cùng với toán tử so sánh?
  2. Mà một trong những Equals ảo() hoặc Equals IEquatable của() sholud được sử dụng .. (nói nếu chúng tôi sử dụng lớp bộ sưu tập riêng của chúng tôi)

Trả lời

26

1 - Tham chiếu bằng kiểm tra nếu hai biến kiểu tham chiếu (lớp, không cấu trúc) được gọi cùng một địa chỉ bộ nhớ.

2 - Phương thức equals() ảo sẽ kiểm tra xem hai đối tượng có tương đương hay không.Chúng ta hãy nói rằng bạn có lớp học này:

class TestClass{ 
    public int Property1{get;set} 
    public int Property2{get;set} 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 
} 

và bạn nhanh chóng 2 đối tượng từ lớp rằng:

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 

mặc dù hai đối tượng không phải là những ví dụ tương tự của TestClass, cuộc gọi đến o1.Equals (o2) sẽ trả về đúng sự thật.

3 - Phương thức tĩnh Equals được sử dụng để xử lý sự cố khi có giá trị null trong séc. Hãy tưởng tượng này, ví dụ:

TestClass o1 = null; 
var o2 = new TestClass{property1 = 1, property2 = 2} 

Nếu bạn cố gắng này:

o1.Equals(o2); 

bạn wil nhận được một NullReferenceException, bởi vì điểm o1 không có gì. Để giải quyết vấn đề này, bạn làm điều này:

Object.Equals (o1, o2);

Phương pháp này được chuẩn bị để xử lý các tham chiếu null.

4 - Giao diện IEquatable được cung cấp bởi .Net, do đó bạn không cần phải thực hiện các phôi bên trong phương thức Bằng của bạn. Nếu trình biên dịch phát hiện ra rằng bạn đã triển khai giao diện trong một lớp cho kiểu bạn đang cố gắng kiểm tra sự bình đẳng, nó sẽ ưu tiên phương thức đó hơn đối tượng Object.Equals (Object). Ví dụ:

class TestClass : IEquatable<TestClass> 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 

    #region IEquatable<TestClass> Members 

    public bool Equals(TestClass other) 
    { 
     return (other.Property1 == this.Property1 && other.Property2 == this.Property2); 
    } 

    #endregion 
} 

bây giờ nếu chúng ta làm điều này:

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 
o1.Equals(o2); 

Các gọi là phương pháp là Equals (TestClass), trước khi Equals (Object).

5 - Toán tử == thường có nghĩa là ReferenceEquals, nó sẽ kiểm tra xem hai biến có trỏ đến cùng một địa chỉ bộ nhớ hay không. Gotcha là toán tử này có thể được ghi đè để thực hiện các loại séc khác. Trong chuỗi, ví dụ, nó kiểm tra nếu hai trường hợp khác nhau là tương đương.

Đây là một liên kết hữu ích để hiểu bình đẳng trong Net tốt hơn:

+0

Tuyệt vời. Các ví dụ thực sự giúp đỡ, nhưng có một lỗi đánh máy trong điểm 4 của bạn, nơi IEquatable.Equals vẫn sử dụng 'conversionObj' – PaulG

+0

Cảm ơn PaulG, nó đã được sửa! =] – mverardo

29

Các ReferenceEquals() phương pháp.

Điều này được sử dụng để kiểm tra nếu hai biến cho điểm (tham chiếu biểu tượng) cho cùng một đối tượng. Nó theo nghĩa đen tương đương với ((object)a) == ((object)b). Nếu bạn ghi đè toán tử so sánh (==) thì ReferenceEquals duy trì cách truy cập hành vi mặc định.

Tuy nhiên, nếu bạn đang xử lý loại giá trị (ví dụ: cấu trúc) thì will always return false này. Điều này là do các hộp so sánh từng loại giá trị với một đối tượng mới nên các tham chiếu tự nhiên sẽ không bằng nhau.


Các Equals ảo() phương pháp. (System.Object)

Đây là cách mặc định để so sánh hai đối tượng theo ngữ nghĩa (thuộc bất kỳ loại nào). Mỗi lớp sẽ ghi đè điều này khi họ chọn. Theo mặc định, nó tương đương với một cuộc gọi CLR (InternalEquals) mà về cơ bản so sánh tham chiếu bộ nhớ.

Lưu ý, nếu hai đối tượng trả về true cho Equals() thì GetHashCode() trên mỗi số must be equal. Tuy nhiên, nếu mã băm cho hai đối tượng có giá trị tương đương (ví dụ: obj1.GetHashCode() == obj2.GetHashCode()) thì điều này không không có nghĩa là Equals() là đúng.

Lớp học của bạn thường sẽ triển khai EqualsGetHashCode làm phương tiện phân biệt các phiên bản lớp và phải thực hiện điều này hoặc toán tử == (lý tưởng là cả hai) nếu đó là loại giá trị.

Lưu ý, đối với các loại giá trị, hành vi mặc định EqualsValueType.Equals() nếu bạn nhìn vào Reflector (hoặc đọc the MSDN description) sử dụng phản chiếu để so sánh các thành viên của hai trường hợp giá trị.


Các Equals tĩnh() phương pháp.

Điều này tương đương với return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))) nơi mỗi loại được chuyển đổi thành Object để thử nghiệm. Thử nghiệm của tôi cho thấy các toán tử so sánh quá tải bị bỏ qua, nhưng phương thức Equals của bạn sẽ được sử dụng nếu các đối tượng không rỗng và không phải là tham chiếu tương tự. Như vậy, a.Equals(b) không nhất thiết phải bằng object.Equals(a, b) (đối với các trường hợp trong đó ((object)a) == ((object)b) hoặc a hoặc b là null).


Các Bằng phương pháp từ giao diện IEquatable.

IEquatable cung cấp cách để bạn đối xử so sánh với các trường hợp cùng loại đặc biệt. Có nói rằng Equals phương pháp của bạn should be handling the behaviour the same way:

Nếu bạn thực hiện Equals, bạn nên cũng ghi đè lên các lớp cơ sở triển khai của Object.equals (Object) và GetHashCode để hành vi của họ là phù hợp với của các IEquatable.Equals phương pháp

Nevertheless you should implement IEquatable:

Để xử lý các khả năng mà các đối tượng của một lớp sẽ được lưu trữ trong một mảng hoặc một đối tượng bộ sưu tập chung, nó là một ý tưởng tốt để thực hiện IEquatable để các đối tượng có thể dễ dàng xác định và thao túng.


Việc so sánh toán tử ==

Các toán tử so sánh bằng cách trở về mặc định đúng khi cả hai đối tượng của bạn là những tài liệu tham khảo tương tự.

is not recommended để ghi đè các toán tử so sánh, trừ khi bạn đang đối phó with a value type (trong trường hợp này nó được khuyến khích, cùng với các phương pháp Equals) hoặc một loại tài liệu tham khảo bất biến mà bạn thường sẽ so sánh theo giá trị (ví dụ string). Luôn luôn thực hiện != cùng một lúc (trên thực tế tôi nhận được lỗi requires a matching operator '!=' to also be defined nếu không).


Resources:

+2

xuất sắc trả lời. +1 – RPM1984

0

Đối với nguyên thủy, gắn bó với các nhà điều hành ==. Trong hầu hết các đối tượng được cung cấp trong .NET framework và bất kỳ đối tượng tùy chỉnh nào bạn tạo phương thức .Equals() và toán tử == sẽ chỉ kiểm tra xem hai đối tượng có tham chiếu đến cùng một đối tượng trên vùng heap hay không.

Mục đích của giao diện IEquatable là ghi đè phương thức .Equals() để thay đổi hành vi của nó khỏi kiểm tra bình đẳng tham chiếu để kiểm tra giá trị bình đẳng. Kiểu System.String là một ví dụ về một đối tượng .NET dựng sẵn, thực hiện giao diện này.

Phương thức .ReferenceEquals() cung cấp một cách cho các nhà phát triển đã overriden phương thức .Equals() chuẩn để vẫn có thể kiểm tra hai đối tượng cho bình đẳng tham chiếu.

+2

"Nguyên thủy"? Đây không phải là Java, mang! – Randolpho

1

Mỗi phiên bản bình đẳng hơi khác nhau.

ReferenceEquals kiểm tra tính bình đẳng tham chiếu.

virtual Equals bằng cách kiểm tra mặc định cho bình đẳng tham chiếu cho loại lớp và bình đẳng giá trị cho các loại cấu trúc. Nó có thể được ghi đè để xác định sự bình đẳng khác nhau, nếu muốn; và cần được ghi đè cho các loại giá trị.

static Equals chỉ cần gọi virtual Equals, nhưng cũng cho phép đối số null.

IEquatable<T>.Equals là loại tương đương/loại an toàn tương đương cho virtual Equals.

operator== được dự định giống như mặc định virtual Equals, nghĩa là tham chiếu bình đẳng cho loại lớp (trừ khi lớp cũng ghi đè các toán tử khác). Nó cũng nên được ghi đè cho các loại giá trị.

Nếu bạn viết lớp sưu tập của riêng mình, hãy sử dụng IEqualityComparer<T>, mặc định là EqualityComparer<T>.Default. Không sử dụng bất kỳ sự so sánh bình đẳng nào trực tiếp.

+0

thnx .. để giải quyết nghi ngờ về việc triển khai lớp sưu tập riêng của chúng tôi – Gaurav

Các vấn đề liên quan