2013-02-12 74 views
153

Tôi có hai đối tượng trong C# và không biết đó là Boolean hay bất kỳ loại nào khác. Tuy nhiên khi tôi cố gắng so sánh những C# không đưa ra câu trả lời đúng. Tôi đã thử cùng một mã với VB.NET và đã làm điều đó!Tại sao C# không so sánh hai loại đối tượng với nhau nhưng VB không?

Bất cứ ai có thể cho tôi biết cách khắc phục điều này nếu có giải pháp?

C#:

object a = true; 
object b = true; 
object c = false; 
if (a == b) c = true; 
MessageBox.Show(c.ToString()); //Outputs False !! 

VB.NET:

Dim a As Object = True 
Dim b As Object = True 
Dim c As Object = False 
If (a = b) Then c = True 
MessageBox.Show(c.ToString()) '// Outputs True 
+3

nếu bạn thay đổi trình so sánh bình đẳng thành 'a.Equals (b)' thì sao? –

+8

Đây là một câu hỏi hay cho mục đích sư phạm. – Lobo

+10

Bởi vì mã VB.NET của bạn không bằng mã C# của bạn. –

Trả lời

165

Trong C#, các == điều hành (khi áp dụng để tham khảo biểu type) thực hiện một tham khảo kiểm tra bình đẳng trừ khi đó là quá tải . Bạn đang so sánh hai tham chiếu là kết quả của chuyển đổi quyền anh, do đó, đó là những tham chiếu riêng biệt.

CHỈNH SỬA: Với các loại quá tải ==, bạn có thể nhận được hành vi khác - nhưng dựa trên loại biểu thức thời gian biên dịch. Ví dụ, string cung cấp ==(string, string):

string x = new string("foo".ToCharArray()); 
string y = new string("foo".ToCharArray()); 
Console.WriteLine(x == y); // True 
Console.WriteLine((object) x == (object) y); // False 

đây so sánh đầu tiên được sử dụng toán tử quá tải, nhưng thứ hai là sử dụng "mặc định" so sánh tham khảo.

Trong VB, toán tử = hoạt động hiệu quả hơn rất nhiều - nó thậm chí không chỉ tương đương với việc sử dụng object.Equals(x, y), vì những thứ như Option Compare có thể ảnh hưởng đến cách so sánh văn bản.

Về cơ bản, nhà khai thác không hoạt động theo cùng một cách và không phải là nhằm mục đích hoạt động theo cách tương tự.

+17

+1 Tôi biết bạn sẽ ở xung quanh, bạn yêu những loại bí ẩn này câu hỏi :) – AbZy

+3

@AbZy: Tôi hy vọng sẽ có thể cung cấp một giải thích chi tiết hơn về những gì '=' đã làm trong VB, nhưng spec là không rõ ràng khủng khiếp. –

+0

điều thú vị, nhưng thay đổi đối tượng thành hành vi động giống như VB – VladL

4

Các cá thể đối tượng không được so sánh với toán tử "==". Bạn nên sử dụng phương thức "bằng". Với toán tử "==" đang so sánh tham chiếu, chứ không phải đối tượng.

Hãy thử điều này:

public class MyObject 
{ 
    public MyObject(String v) 
    { 
     Value = v; 
    } 
    public String Value { get; set; } 
} 

MyObject a = new MyObject("a"); 
MyObject b = new MyObject("a"); 
if(a==b){ 
    Debug.WriteLine("a reference is equal to b reference"); 
}else{ 
    Debug.WriteLine("a reference is not equal to b reference"); 
} 
if (a.Equals(b)) { 
    Debug.WriteLine("a object is equal to b object"); 
} else { 
    Debug.WriteLine("a object is not equal to b object"); 
} 

Kết quả:

a reference is not equal to b reference 
a object is not equal to b object 

Bây giờ, hãy thử này:

public class MyObject 
{ 
    public MyObject(String v) 
    { 
     Value = v; 
    } 
    public String Value { get; set; } 

    public bool Equals(MyObject o) 
    { 
     return (Value.CompareTo(o.Value)==0); 
    } 
} 
MyObject a = new MyObject("a"); 
MyObject b = new MyObject("a"); 
if(a==b){ 
    Debug.WriteLine("a reference is equal to b reference"); 
}else{ 
    Debug.WriteLine("a reference is not equal to b reference"); 
} 
if (a.Equals(b)) { 
    Debug.WriteLine("a object is equal to b object"); 
} else { 
    Debug.WriteLine("a object is not equal to b object"); 
} 

Kết quả:

a reference is not equal to b reference 
a object is equal to b object 
+1

Điều này đơn giản chỉ vì bạn không ghi đè' operator == '. Nếu bạn overrode rằng nhà điều hành và không bằng thì sản lượng của bạn sẽ được đảo ngược. Không có gì vốn có để so sánh tham chiếu về 'toán tử ==' và không có gì vốn có về so sánh các giá trị trong 'Equals'. Chúng chỉ là hai cách để xác định sự bình đẳng; cả hai đều có triển khai mặc định so sánh tham chiếu và cả hai có thể được ghi đè để thực hiện bất kỳ điều gì bạn muốn chúng thực hiện. Điểm khác biệt duy nhất là 'Equals' là virtual và' operator == 'thì không. – Servy

+1

@Servy: Lưu ý rằng bạn không thể * ghi đè * '==' - bạn chỉ có thể * quá tải *. –

+0

@JonSkeet Bạn đúng, sai lầm của tôi. – Servy

3

Vấn đề là toán tử == trong C# là một cuộc gọi đến phương thức tĩnh (tốt, có thể không phải về mặt kỹ thuật, nhưng có thể là như vậy) dựa trên loại thời gian biên dịch của hai tham số. Các kiểu thời gian chạy thực tế của các đối tượng đó không quan trọng.

Dựa trên loại thời gian biên dịch đó, trình biên dịch sẽ xác định việc triển khai thực hiện operator == để sử dụng. Nó có thể sử dụng triển khai thực hiện object mặc định, nó có thể sử dụng một trong các tình trạng quá tải số do ngôn ngữ cung cấp hoặc có thể do người dùng xác định triển khai.

Điều này khác với VB trong đó VB không xác định việc triển khai tại thời gian biên dịch. Nó đợi cho đến khi chạy và kiểm tra hai tham số mà nó được đưa ra để xác định việc thực thi của toán tử == mà nó sẽ sử dụng.

Mã của bạn chứa các giá trị boolean, nhưng chúng nằm trong các biến thuộc loại object. Bởi vì biến số thuộc loại object, trình biên dịch C# sử dụng triển khai object của ==, so sánh các tham chiếu , không phải là trường hợp đối tượng. Vì các giá trị boolean là các hộp, chúng không có cùng tham chiếu, mặc dù các giá trị của chúng giống nhau.

Mã VB không quan tâm loại biến đó là gì. Nó đợi cho đến khi chạy và sau đó kiểm tra hai biến, thấy rằng chúng là thực sự là của cả hai kiểu boolean, và do đó sử dụng toán tử boolean ==. Việc thực thi đó so sánh các giá trị của các boolean, không phải các tham chiếu của chúng (và các boolean sẽ được unboxed trước khi gọi điện thoại gọi toán tử đó, vì vậy một so sánh tham chiếu thậm chí không có ý nghĩa nữa). Bởi vì các giá trị của boolean là như nhau, nó trả về true.

+0

Điều đó có vẻ tốt cho C#; Tôi không biết chính xác những gì '=' làm trong VB để nói chắc chắn. –

+0

@JonSkeet Fair đủ. – Servy

+0

Mỗi http://msdn.microsoft.com/en-us/library/cey92b0t(v=vs.110).aspx, trong phần "Lập trình không kiểu với toán tử so sánh quan hệ": '=', cùng với tất cả các quan hệ khác các toán tử so sánh như '<', '> =', v.v., được xử lý đặc biệt khi cả hai bên của toán tử là 'Object'. Việc xử lý đặc biệt này được thực hiện để các lập trình viên VB6, những người đã quen với việc sử dụng một kiểu được gọi là 'Biến thể' trong VB.NET trước, có thể sử dụng' Object' trong VB.Net theo cách họ đã sử dụng 'Biến thể' trước. – rskar

79

Ngoài câu trả lời của Jon điều này giải thích C# bên của sự vật, đây là những gì VB không:

Trong VB với Option Strict On, một sự so sánh qua =luôn xét nghiệm cho giá trị bình đẳng và không bao giờ cho bình đẳng tham khảo. Trên thực tế, mã của bạn thậm chí không biên dịch khi bạn chuyển đổi Option Strict OnSystem.Object không xác định Operator=. Bạn nên luôn luôn có tùy chọn này trên, nó bắt lỗi hiệu quả hơn một flytrap venus (mặc dù trong trường hợp cụ thể của bạn hành vi lỏng lẻo này thực sự làm điều đúng).

Trong thực tế, với Option Strict On, VB cư xử thậm chí khắt khe hơn so với C#: Trong C#, a == bhai gây nên một cuộc gọi đến SomeType.operator==(a, b) hoặc, nếu điều này không tồn tại, chảy sệ so sánh bình đẳng tham khảo (tương đương với gọi số object.ReferenceEquals(a, b)).

Trong VB, việc so sánh a = bluôn luôn gọi toán tử bằng. Nếu bạn muốn sử dụng so sánh bình đẳng tham chiếu, bạn phải sử dụng a Is b (tức là, một lần nữa, giống như Object.ReferenceEquals(a, b)).


1) Dưới đây là một dấu hiệu tốt vì sao sử dụng Option Strict Off là một ý tưởng tồi: Tôi đã sử dụng VB.NET trong gần một thập kỷ, từ trước khi phát hành chính thức của .NET cho đến khi một vài năm trước đây, và tôi hoàn toàn không có ý tưởng những gì a = b thực hiện với Option Strict Off. Nó thực hiện một số loại so sánh bình đẳng, nhưng những gì chính xác xảy ra và tại sao, không có ý tưởng. Nó phức tạp hơn so với tính năng dynamic của C#, mặc dù (vì điều đó phụ thuộc vào API được ghi chép đầy đủ).Here’s what the MSDN says:

Option Strict On cung cấp gõ mạnh, ngăn chặn chuyển đổi loại hình ngoài ý muốn với sự mất mát dữ liệu, không cho phép vào cuối ràng buộc, và cải thiện hiệu suất, sử dụng của nó được khuyến khích mạnh mẽ.

2) Jon đã đề cập đến một ngoại lệ, chuỗi, khi so sánh bình đẳng thực hiện một số điều khác vì lý do tương thích ngược.

+4

+1. Tôi nghĩ đây là một trường hợp mà các nhà thiết kế của VB.NET đã thành công trong việc tạo ra ngôn ngữ "chỉ làm việc" cho các lập trình viên đến từ VB6 và VBA, nơi OOP ít nổi bật hơn và do đó khái niệm về bình đẳng tham chiếu ít quan trọng hơn nhiều. Một coder VB có thể viết mã làm việc tốt mà không cần suy nghĩ nhiều về các đối tượng và vv. –

+5

+1 Đây không phải là upvoted nhiều như nó thực sự cần. Không sử dụng 'Tùy chọn Nghiêm ngặt On' phải được xem là phạm tội hình sự ... –

+1

@JohnMGant: Người lập trình không hiểu được ý nghĩa của danh tính tham chiếu có thể viết mã xảy ra để hoạt động nhưng không thực sự biết những thứ có thể thay đổi một cách an toàn, những thay đổi sẽ luôn phá vỡ mọi thứ, và những thay đổi có thể có tác dụng nhưng gây ra những tác dụng phụ không mong muốn (ví dụ: gây ra những gì cần tham chiếu đến các đối tượng có thể thay đổi khác nhau có cùng trạng thái thay vào đó cùng một đối tượng). Nếu các đối tượng ít khi bị đột biến, sự thay đổi đó có thể không gây ra bất kỳ vấn đề tức thời nào, nhưng có thể làm cho các lỗi khó tìm thấy phát sinh sau này. – supercat

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