2013-08-05 22 views
8

Tôi có một lớp với hai ghi đè cho toán tử ==, để so sánh nó với các phiên bản khác của lớp này và so sánh với thể hiện chuỗi.Kiểm tra rỗng không rõ ràng đối với một lớp với một số ghi đè cho toán tử ==

class SomeClass 
{ 
    string value; 
    public SomeClass (string _Value) 
    { 
     value = _Value; 
    } 

    static public bool operator == (SomeClass C1, SomeClass C2) 
    { 
     return C1.value == C2.value; 
    } 

    static public bool operator != (SomeClass C1, SomeClass C2) 
    { 
     return C1.value != C2.value; 
    } 

    static public bool operator == (SomeClass C1, string C2) 
    { 
     return C1.value == (string) C2; 
    } 

    static public bool operator != (SomeClass C1, string C2) 
    { 
     return C1.value != (string) C2; 
    } 
} 

Tuy nhiên, khi tôi cố gắng để so sánh lớp này để null:

 Console.WriteLine(someObject == null); 

tôi nhận được lỗi sau:

Error CS0121: The call is ambiguous between the following methods or properties: `SomeClass.operator ==(SomeClass, SomeClass)' and `SomeClass.operator ==(SomeClass, string)' 

Làm thế nào tôi nên xác định == tôi sẽ ghi đè vì vậy tôi có thể vẫn còn null-kiểm tra trường hợp của lớp này?

+1

Có lẽ có điều gì đó thông minh bạn có thể làm với một [ null coalesce] (http://msdn.microsoft.com/en-us/library/ms173224.aspx) – tnw

Trả lời

6

Vì bạn đang sử dụng null theo nghĩa đen, trình biên dịch không biết nên gọi phương thức nào vì cả hai stringSomeClass đều có thể rỗng.

Một kỹ thuật để buộc trình biên dịch chọn một trong các phương pháp là đánh máy null.

Console.WriteLine(someObject == ((SomeClass)null)); 

Hoặc tốt hơn, thay vì sử dụng null một cách rõ ràng, sử dụng từ khóa default để có được những giá trị null (vì default(T) là null khi T là một loại tài liệu tham khảo).

Console.WriteLine(someObject == default(SomeClass)); 
+0

Điều đó được chứng minh là cách thanh lịch nhất, cảm ơn. Mặc dù (SomeClass) null có thể trông lạ trong mã (tôi chắc chắn sẽ ngạc nhiên bởi điều đó cho đến ngày hôm nay), tôi nghĩ rằng nó vẫn khá tốt cho khả năng đọc: nếu người duy trì quyết định khám phá nó, anh ta sẽ phải gỡ nó ra xem lỗi, và anh ta (được cho là) ​​sẽ dễ dàng hiểu được mục đích của "phép thuật" này. –

+1

@golergka Bây giờ, với việc thực hiện thực tế bạn đã cho thấy trong câu hỏi, quá tải của bạn '==' cả hai có thể phát nổ với một 'NullReferenceException'. Có lẽ bạn muốn C# được xây dựng trong quá tải 'operator == (đối tượng, đối tượng)' (không thực sự là một phương pháp trong IL)? Tôi nghĩ bạn đã làm. Vì vậy, đó là 'someObject == (đối tượng) null' hoặc' (đối tượng) someObject == null' hoặc '(đối tượng) someObject == (đối tượng) null' (cả ba đều đi tới' == 'được xây dựng sẵn, không phải bất kỳ nhà khai thác nào của bạn). –

4

Thay vì xác định hai nhà khai thác bình đẳng, bạn có thể tạo một chuyển đổi ngầm giữa stringSomeClass:

class SomeClass 
{ 
    string value; 
    public SomeClass(string _Value) 
    { 
     value = _Value; 
    } 
    static public bool operator ==(SomeClass C1, SomeClass C2) 
    { 
     return C1.value == C2.value; 
    } 
    static public bool operator !=(SomeClass C1, SomeClass C2) 
    { 
     return C1.value != C2.value; 
    } 

    public static implicit operator string(SomeClass instance) 
    { 
     return instance.value; 
    } 

    public static implicit operator SomeClass(string str) 
    { 
     return new SomeClass(str); 
    } 
    //TODO override Equals and GetHashCode to use `value` 
} 

Bây giờ khi bạn so sánh giá trị null không có vấn đề nhập nhằng.

Điều này cũng có tác dụng phụ làm cho các lớp chuyển đổi hoàn toàn với nhau ở mọi nơi khác, nhưng dựa trên ngữ cảnh dường như không phải là điều xấu.

+1

Đó là một ý tưởng hay. Tuy nhiên, trong trường hợp cụ thể này, mục tiêu của lớp (rõ ràng không phải là lớp được trình bày trong câu hỏi) là thay thế lớp chuỗi sao cho nó sẽ cung cấp chức năng tương tự với hợp đồng bổ sung, và để đảm bảo rằng chuỗi không được sử dụng trong một ngữ cảnh nhất định - Vì vậy, chuyển đổi tiềm ẩn sẽ đánh bại mục đích của nó. Tuy nhiên, nói chung, đó là một giải pháp tuyệt vời, cảm ơn. –

+0

Nói 'someObject == null' không còn mơ hồ (và không đi qua' toán tử ngầm'), nhưng dĩ nhiên việc thực thi 'operator ==' dẫn đến một 'NullReferenceException' chắc chắn vì' C2' sẽ là 'null'. –

-1

Bạn có thể chuyển tham số thứ hai làm "đối tượng" và kiểm tra loại của nó trước khi quyết định nên thực hiện bình đẳng nào.

static public bool operator == (SomeClass C1, object C2) 
{ 
    if(C2 is SomeClass) 
    return C1.value == ((SomeClass)C2).value; 
    else if (C2 is string) 
    return C1.value == (string) C2; 
} 
+0

Nhưng sau đó bạn cũng có thể vượt qua trong một 'bool', và điều đó thậm chí không nên biên dịch. – Servy

+0

mã rõ ràng là một phần vì nó cần một kiểm tra để xử lý các loại không được hỗ trợ, mà tôi không biết làm thế nào OP muốn xử lý – Konstantin

+0

Reglardless, nó sẽ chỉ là một kiểm tra thời gian chạy, không phải là một thời gian kiểm tra biên dịch. Nó phải là một kiểm tra thời gian biên dịch. – Servy

1

Đối với những người đến muộn, vui lòng tham khảo dưới đây để biết câu trả lời có thể chấp nhận được trong nhận xét từ @Jeppe Stig Nielsen.

Các op đã yêu cầu cụ thể về điều hành trọng ==, tuy nhiên, tôi tin rằng đây là một phần quan trọng của thông tin khi trọng các toán tử == và tin rằng câu trả lời đúng để tham khảo trong tương lai nên là: -

Console.WriteLine((object)someObject == null); 

Sử dụng câu trả lời được chấp nhận và thực hiện cả hai == và Equals trong đối tượng của bạn, bạn sẽ tiếp tục gặp lỗi tương tự. Tốt nhất để so sánh với null ở đối tượng mức thấp nhất, theo cách đó bạn đang so sánh 'đối tượng' với giá trị rỗng và tất cả sự mơ hồ được loại bỏ khỏi so sánh.

Dưới đây là lý do và giải quyết theo thực hiện trong MSDN: Guidelines for Overriding Equals() and Operator ==

Hãy xem xét những điều sau đây, tham khảo ý kiến ​​trong việc thực hiện Equals: -

class SomeClass 
{ 
    string value; 
    public SomeClass(string _Value) 
    { 
     value = _Value; 
    } 

    static public bool operator ==(SomeClass C1, SomeClass C2) 
    { 
     return C1.value == C2.value; 
    } 

    public override bool Equals(SomeClass C1) 
    { 
     // causes error due to unsure which operator == to use the SomeClass == or the object == 
     // Actual error: Operator '==' is ambiguous on operands of type 'SomeClass' and '<null>' 
     if (C1 == null) 
      return false; 

     // Give same error as above 
     if (C1 == default(SomeClass)) 
      return false; 

     // Removes ambiguity and compares using base objects == to null 
     if ((object)C1 == null) 
      return false; 

     return value == C1.value; 
    } 
} 
Các vấn đề liên quan