2010-03-22 15 views
25

Tôi đã gặp phải tình huống này ngày hôm nay. Tôi có một đối tượng mà tôi đang thử nghiệm cho sự bình đẳng; phương thức Create() trả về việc thực hiện lớp con của MyObject.Khi nào có thể == b là sai và a.Equals (b) đúng?

MyObject a = MyObject.Create(); 
MyObject b = MyObject.Create(); 

a == b; // is false 
a.Equals(b); // is true 

Note Tôi cũng có Equals trên một thanh cuộn() trong việc thực hiện phân lớp, mà làm một kiểm tra rất cơ bản để xem có hay không các đối tượng thông qua trong là null và là loại của lớp con. Nếu cả hai điều kiện được đáp ứng, các đối tượng được coi là bằng nhau.

Điều hơi kỳ lạ khác là bộ phận thử nghiệm của tôi làm một số xét nghiệm tương tự như

Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar 

và kết quả dự kiến ​​được quan sát. Vì vậy, tôi đoán rằng NUnit sử dụng a.Equals (b) dưới bìa, chứ không phải là một == b như tôi đã giả định.

Lưu ý phụ: Tôi lập trình bằng hỗn hợp .NET và Java, vì vậy tôi có thể đang trộn lẫn các kỳ vọng/giả định của mình tại đây. Tôi nghĩ, tuy nhiên, rằng một == b làm việc nhất quán hơn trong NET hơn nó đã làm trong Java, nơi bạn thường phải sử dụng bằng() để kiểm tra bình đẳng.

CẬP NHẬT Đây là việc thực hiện các Equals(), theo yêu cầu:

b kiểm tra
public override bool Equals(object obj) { 
    return obj != null && obj is MyObjectSubclass; 
} 
+3

Chúng tôi có thể thấy việc bạn triển khai ghi đè .Equals() – msarchet

+1

Vui lòng đăng mã cho hàm Equals đã ghi đè hay không. – AxelEckenberger

+0

khi một nhưng không phải cả hai đều được ghi đè lên tất nhiên :) – RCIX

Trả lời

32

Sự khác biệt chính giữa ==Equals== (giống như tất cả các nhà khai thác) không phải là đa hình, trong khi Equals (giống như bất kỳ chức năng ảo) là.

Theo mặc định, các loại tham chiếu sẽ nhận được kết quả giống hệt nhau cho ==Equals, vì cả hai đều so sánh tham chiếu. Nó cũng chắc chắn có thể mã logic vận hành của bạn và Equals logic hoàn toàn khác nhau, mặc dù điều đó dường như vô nghĩa để làm. Dấu hiệu lớn nhất xuất hiện khi sử dụng toán tử == (hoặc bất kỳ) ở mức cao hơn logic mong muốn được tuyên bố (nói cách khác, tham chiếu đối tượng dưới dạng lớp cha hoặc không xác định rõ toán tử hoặc xác định nó khác với đúng lớp). Trong những trường hợp như vậy, logic của lớp là được tham chiếu như được sử dụng cho các toán tử, nhưng logic cho Equals đến từ bất kỳ lớp nào đối tượng thực sự là .

tôi muốn nêu một cách dứt khoát rằng, chỉ duy nhất dựa trên thông tin trong câu hỏi của bạn, hoàn toàn không có lý do gì để nghĩ hay cho rằng Equals so sánh giá trị so với tài liệu tham khảo. Thật dễ dàng để tạo một lớp học như vậy, nhưng đây là không phải là đặc tả ngôn ngữ.

Post-câu hỏi-edit chỉnh sửa

triển khai của bạn của Equals sẽ trở lại đúng với bất kỳ trường hợp không null của lớp học của bạn. Mặc dù cú pháp làm cho tôi nghĩ rằng bạn không, bạn có thể nhầm lẫn từ khóa is C# (xác nhận loại) với từ khóa is trong VB.NET (xác nhận tính bình đẳng tham chiếu). Nếu đó thực sự là trường hợp, thì bạn có thể thực hiện so sánh tham chiếu rõ ràng trong C# bằng cách sử dụng Object.ReferenceEquals(this, obj).

Trong mọi trường hợp, đây là lý do tại sao bạn thấy true cho Equals, vì bạn đang chuyển sang một phiên bản không trống của lớp học của bạn.

Ngẫu nhiên, nhận xét của bạn về NUnit sử dụng Equals là đúng vì lý do tương tự; vì các toán tử không đa hình, sẽ không có cách nào cho một lớp cụ thể xác định hành vi bình đẳng tùy chỉnh nếu hàm Assert được sử dụng ==.

+0

Đây là câu trả lời đúng duy nhất cho đến nay – Lee

+4

Đây có lẽ là câu trả lời hay nhất mà tôi từng có cho bất kỳ câu hỏi nào tôi đã hỏi về SO. Cảm ơn Adam, tôi muốn tôi có thể upvote bạn nhiều hơn chỉ một lần! – alastairs

+1

+1 để giải quyết ghi đè Bằng sau khi OP cập nhật câu hỏi bằng mã. –

6

một == nếu họ tham khảo cùng một đối tượng.

a.Equals (b) so sánh nội dung.

Đây là một link đối với bài viết của Jon Skeet từ năm 2004 giải thích tốt hơn.

+1

Đúng cho chuỗi. Tổng quát cho các lớp khác, 'a.Equals (b)' trả về kết quả của phương thức Equals của 'a'. –

+0

Trừ khi bạn quá tải toán tử ==. +1 –

+4

-1. Hoàn toàn không có lý do gì để giả định rằng 'Equals' ở đây quyết định sự bình đẳng dựa trên việc kiểm tra sâu dữ liệu của đối tượng. –

0

Tôi tin rằng a == b sẽ kiểm tra xem đối tượng được tham chiếu có giống nhau không.

Thông thường để xem liệu giá trị có giống nhau không. Các dấu phẩy (b) được sử dụng (điều này thường cần được ghi đè để hoạt động).

+1

Trừ khi lớp ghi đè toán tử ==. –

+1

Điều này không đúng. Không có sự khác biệt ngữ nghĩa cấp độ ngôn ngữ giữa '==' và 'Bằng'. –

1

Trong Java một tấm séc == b nếu tài liệu tham khảo của hai đối tượng là equals (rougly, nếu hai đối tượng đều cùng một đối tượng "bí danh")

a.equals (b) so sánh các giá trị thể hiện bằng hai vật thể.

+1

Đúng trong Java, không phải lúc nào cũng đúng trong C#. –

0

Các "==" hoạt động kiểm tra bình đẳng tuyệt đối (trừ khi quá tải); nghĩa là, nó kiểm tra xem hai đối tượng có là cùng một đối tượng hay không. Điều đó chỉ đúng nếu bạn giao cho người khác, tức là.

MyObject a = MyObject.Create(); 
MyObject b = a; 

Chỉ cần đặt tất cả thuộc tính của hai đối tượng bằng nhau không có nghĩa là chính các đối tượng đó. Dưới mui xe, toán tử "==" so sánh là địa chỉ của các đối tượng trong bộ nhớ. Một hiệu ứng thực tế của điều này là nếu hai đối tượng thực sự bằng nhau, việc thay đổi một thuộc tính trên một trong số chúng cũng sẽ thay đổi nó trên cái kia, trong khi nếu chúng chỉ giống nhau ("Bằng"), thì sẽ không. Điều này hoàn toàn nhất quán khi bạn hiểu nguyên tắc.

+0

Điều này đúng * theo mặc định cho các loại tham chiếu *. Đó không phải là sự thật tuyệt đối. –

1

Cả hai đều thực hiện tương tự trừ khi chúng được quá tải cụ thể trong đối tượng để thực hiện điều gì đó khác.

Trích dẫn từ Jon Skeet Article được đề cập ở nơi khác.

Các Bằng phương pháp chỉ là một ảo một định nghĩa trong System.Object, và ghi đè bởi bất cứ lớp chọn để làm như vậy. Toán tử == là toán tử có thể bị quá tải bởi các lớp , nhưng thường có hành vi nhận dạng .

Từ khóa ở đây là USUALLY. Chúng có thể được viết để làm bất cứ điều gì mà lớp cơ bản mong muốn và không có cách nào để chúng phải làm như vậy.

3

Bạn khá nhiều đã trả lời câu hỏi của bạn mình:

Tôi cũng có trên một thanh cuộn Equals() trong việc thực hiện phân lớp, mà làm một kiểm tra rất cơ bản để xem có hay không thông qua trong đối tượng là null và thuộc loại của lớp con. Nếu cả hai điều kiện được đáp ứng, các đối tượng được coi là bằng nhau.

Nhà điều hành == chưa được quá tải - vì vậy nó trở false từ ab là những đối tượng khác nhau. Nhưng a.Equals đang gọi ghi đè của bạn, có thể là trả về true vì không phải a cũng không phải b là rỗng và cả hai đều thuộc loại của lớp con.

Vì vậy, câu hỏi của bạn là "Khi nào có thể == b là false và a.Equals (b) true?" Câu trả lời của bạn trong trường hợp này là: khi bạn mã hóa nó một cách rõ ràng!

+1

Là một điểm sửa chữa, các toán tử * bị quá tải *, không * ghi đè * (vì chúng là tĩnh). Không có sự đa hình với các toán tử, vì vậy sẽ dễ dàng tạo ra một kịch bản trong đó logic giống hệt nhau trong toán tử '==' và phương thức 'Equals' sẽ tạo ra các kết quả khác nhau. –

+0

Ok, do đó, bằng cách mã hóa các đối tượng của tôi theo cách này, tôi đã phá vỡ một cách rõ ràng Equals/==. Đây có phải là một mùi mã cho biết thiết kế có cần suy nghĩ lại không? – alastairs

+0

@alastairs: Nếu bạn muốn * bất kỳ hai trường hợp không null nào thuộc loại * của bạn được coi là bằng nhau, thì bạn đã mã hóa chính xác chức năng của mình. –

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