2016-07-13 21 views
14

Hãy xem xét đoạn mã sau đây.Tại sao so sánh hai chuỗi là đối tượng gây ra kết quả không mong muốn

object str = new string(new char[] { 't', 'e', 's', 't' }); 
object str1 = new string(new char[] { 't', 'e', 's', 't' }); 
Console.WriteLine(str==str1); // false 
Console.WriteLine(str.Equals(str1)); // true 

Tôi hiểu các nhà điều hành bình đẳng làm việc ở đây rằng khi chúng ta đã mặc nhiên đúc để phản đối, các nhà điều hành bình đẳng đang kiểm tra các tài liệu tham khảo của cả hai nếu họ đều bình đẳng và trả về false.

Nhưng tôi đang bối rối trên trang thứ hai, trả về vẻ thật giống như đang gọi Equals ghi đè thực hiện được cung cấp bởi loại chuỗi và nó kiểm tra nội dung của chuỗi nếu chúng bằng nhau.

Câu hỏi của tôi là lý do tại sao nó không kiểm tra sự bình đẳng nội dung cho nhà điều hành là tốt, loại thực tế của họ là chuỗi không phải là đối tượng. đúng ?

trong khi mã follwing kết quả đầu ra ture cho cả hai:

object str = "test"; 
object str1 = "test"; 
Console.WriteLine(str==str1); // true 
Console.WriteLine(str.Equals(str1)); // true 
+1

Cuộc gọi đến các hàm hoặc biến luôn gần nhất với lớp thực tế của đối tượng. Các cuộc gọi đến 'Equals' do đó gọi' string.Equals' được định nghĩa để so sánh nội dung của chuỗi, thay vì 'object.Equals' mặc định. Nếu bạn hoàn toàn muốn sử dụng 'Equals' của' object', bạn có thể sử dụng '(str as object) ?. Equals (str1 as object)'. – Didii

+2

@ khlr Bạn nên thêm rằng như là một câu trả lời, những người hiện đang có loại thiếu điểm ** tại sao ** nó đang xảy ra –

+0

Nhưng nó sai - chuỗi KHÔNG PHẢI là GIÁ TRỊ. –

Trả lời

32

Với:

Console.WriteLine(str==str1); // false 

nó được xác định tại thời gian biên dịch mà C# được xác định trước (chính thức) quá tải của operator == để sử dụng. Kể từ strstr1được khai báoobject, quá tải operator ==(object, object) được chọn. Điều này được cố định tại thời gian biên dịch. Chỉ vì các loại thời gian chạy thực tế xảy ra cụ thể hơn, điều đó không thay đổi. Nếu bạn muốn ràng buộc tại thời gian chạy, hãy sử dụng Console.WriteLine((dynamic)str == (dynamic)str1); /* true */ để thay thế.

Với:

Console.WriteLine(str.Equals(str1)); // true 

bạn gọi một ảo phương pháp trên object. Ảo có nghĩa là nó sẽ đi đến bất cứ điều gì override là có liên quan tại thời gian chạy. Lớp System.String có ghi đè và từ str sẽ có loại thời gian chạy System.String, ghi đè sẽ được sử dụng bởi "công văn ảo".


Về việc bổ sung để dưới cùng của câu hỏi của bạn: Tình hình đó là khác nhau vì chuỗi interning. Việc thực hiện chuỗi là một tối ưu hóa trong đó cùng một cá thể vật lý được sử dụng cho các chuỗi riêng biệt chính thức có giá trị giống hệt nhau. Khi bạn có hai chuỗi có giá trị được đưa ra trong mã nguồn, việc thực hiện chuỗi sẽ "tối ưu hóa" và thực hiện hai tham chiếu đến cá thể giống nhau. Điều này thường vô hại vì các chuỗi được đảm bảo là không thay đổi. Vì vậy, thông thường bạn không quan tâm nếu nó là cùng một trường hợp hoặc một trường hợp khác với giá trị giống hệt nhau. Nhưng trong ví dụ của bạn, chúng tôi có thể "tiết lộ" việc thực tập.

Lưu ý: Việc thực hiện chuỗi không liên quan đến câu hỏi ban đầu của bạn. Chỉ sau khi bạn thêm một ví dụ mới cho câu hỏi của bạn, việc thực hiện chuỗi ký tự trở nên có liên quan.

+0

Cảm ơn, nó có ý nghĩa –

+0

có, tôi hiểu tôi đã thêm rằng đối với người đọc trong tương lai gặp vấn đề này, bây giờ câu trả lời của bạn hữu ích hơn –

+0

Ồ, điều đó có vẻ giống như một sai lầm khủng khiếp đối với ngôn ngữ OO. Nghiêm túc, phương thức được gọi không phải là một phương thức lớp cơ sở chỉ vì bạn đã khai báo đối tượng như là một cá thể của lớp cơ sở. Tổng. –

-3

Sự giúp đỡ để String.Equals phương pháp được đưa ra như là một nhận xét:

Phương pháp này thực hiện một thứ tự (case-sensitive và văn hóa -không so sánh).

Vì vậy, việc so sánh được thực hiện bằng cách kiểm tra chuỗi char bằng char, do đó cho đúng.

+2

Nhưng Ehsan đang sử dụng 'Object.Equals', không phải' String.Equals'. –

+0

@GrantWinney Vì 'Equals' là một phương thức ảo và' String' có một ghi đè cho 'Equals',' String.Equals' là một kết thúc được gọi.Tuy nhiên, '==' là phiên bản 'Object'. –

1

Tôi tin rằng đó là vì các String==operator chỉ mất string loại như thông số, trong khi .Equalsmethod mất object loại như thông số.

Vì chuỗi == chỉ lấy string loại làm tham số, độ phân giải quá tải chọn đối tượng == toán tử để sử dụng để so sánh.

1

Điều này xảy ra vì chuỗi nội trú; khi bạn viết:

object str = "test"; 
object str1 = "test"; 
Console.WriteLine(str==str1); 

này hoạt động như mong đợi như là hai chuỗi nội bộ và âm thầm sao chép vào một vị trí bởi trình biên dịch để hai con trỏ sẽ thực sự trỏ đến cùng đối tượng.

Nếu bạn tạo chuỗi từ một chuỗi ký tự, trình biên dịch không đủ thông minh để hiểu ý định của bạn và nó tương đương với trên, vì vậy, là một chuỗi tham chiếu loại tham chiếu, khác nhau đối tượng trong bộ nhớ.

Hãy nhìn vào bài viết này: https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/

Các Equals phương pháp được ghi đè trong chuỗi, do đó nó được so sánh nội dung thực tế của chuỗi chứ không phải là địa chỉ như == (ReferenceEquals) thực hiện trong trường hợp của bạn là loại đối tượng.

+2

@ HenkHolterman nếu bạn đọc toàn bộ câu trả lời của tôi, bạn sẽ thấy rằng nó được viết ở đó. –

+0

Tôi đã đề cập đến phần đầu tiên khi mọi người mong đợi các chuỗi bằng với một chuỗi khác chỉ vì chúng có cùng các ký tự khi chúng là các loại tham chiếu. "Điều này xảy ra" có nghĩa là giá trị ** đúng ** của sự so sánh chỉ xảy ra đối với interning. –

+1

Câu trả lời không nói rõ: điều này luôn xảy ra, có thể viết "đôi khi" sẽ tự cứu bản thân cuộc thảo luận vô tận này. –

3

Khi == được sử dụng trên biểu thức đối tượng loại, nó sẽ giải quyết thành System.Object.ReferenceEquals.

Bằng chỉ là một phương pháp ảo và hoạt động như vậy, vì vậy phiên bản ghi đè sẽ được sử dụng (trong đó, đối với loại chuỗi so sánh nội dung).

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