2012-03-07 8 views
6

Hãy nói rằng chúng tôi có lớp học này:đúc ngầm của một đối tượng chuỗi, để sử dụng trong một Hashtable

public class Moo 
{ 
    string _value; 

    public Moo(string value) 
    { 
     this._value = value; 
    } 

    public static implicit operator string(Moo x) 
    { 
     return x._value; 
    } 

    public static implicit operator Moo(string x) 
    { 
     return new Moo(x); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj is string) 
      return this._value == obj.ToString(); 
     else if (obj is Moo) 
      return this._value == ((Moo)obj)._value; 
     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     return _value.GetHashCode(); 
    } 
} 

Nếu tôi thêm một đối tượng kiểu này cho một Hashtable, sau đó tôi có thể tìm thấy các đối tượng sử dụng chuỗi giống hệt nhau.
Nhưng nếu Hashtable có chứa chuỗi không phải là đối tượng, nó không tìm thấy nó khi tôi vượt qua đối tượng.

Moo moo = new Moo("abc"); 
bool result1 = moo == "abc";     //true 
bool result1a = moo.Equals("abc");    //true 
bool result2 = "abc" == moo;     //true 
bool result2a = "abc".Equals(moo);    //true 
bool result2b = ((object)"abc").Equals(moo); //false 

Hashtable hash = new Hashtable(); 
hash[moo] = 100; 
object result3 = hash[moo];      //100 
object result4 = hash["abc"];     //100 

hash = new Hashtable(); 
hash["abc"] = 100; 
object result5 = hash[moo];      //null!!!! 
object result6 = hash["abc"];     //100 

Tôi đã cố gắng ghi đè toán tử == và nó không có sự khác biệt.
Có thể sử dụng tính năng đúc ngầm trong Hashtable theo cách này không?

+2

Bạn đang vi phạm một trong các thuộc tính thiết yếu của Equals: "x.Equals (y) trả về cùng giá trị với y.Equals (x)." – CodesInChaos

Trả lời

5

Trước tiên, tại sao bạn sử dụng thẻ bắt đầu bằng # là?

Bất kể vấn đề của bạn là bắt buộc phải gọi số ((object)"abc").Equals(moo), trả về false, tất nhiên. Bạn có thể ghi đè hành vi đó bằng cách chuyển thực hiện của riêng bạn IEqualityComparer đến một trong các nhà xây dựng HashTable với thông số IEqualityComparer.

Vì, như bạn đã lưu ý, bạn đang cố gắng tránh sửa đổi mã cũ, có thể bạn không thể thay thế bảng băm hiện có bằng bảng băm có IEqualityComparer tùy chỉnh. Nếu đó là sự thật, thì tôi nghĩ câu trả lời là bạn không thể làm những gì bạn muốn làm.

Vì bạn đang phát triển lớp "moo" này, tôi cho rằng bạn có quyền kiểm soát mã chuyển lớp moo vào chỉ mục của bảng băm. Nếu đó là sự thật, bạn chỉ có thể gọi ToString() trên đối tượng bạn đang chuyển đến người lập chỉ mục và tất nhiên, ghi đè ToString trong Moo.

+1

Không, "abc" .Equals (moo) trả về true. Và tôi đang mắc kẹt bằng cách sử dụng Hashtable bởi vì tôi đang cố gắng thay đổi mã kế thừa mà không cần phải, er, thay đổi mã. – demoncodemonkey

+2

'" abc ".Equals (moo)' trả về true cho tôi. Nếu bạn gán 'moo' vào một cá thể' object' mặc dù - '" abc ".Equals (mooObj)' trả về false. – BrokenGlass

+3

@demoncodemonkey: '" abc ".Equals (moo)' chỉ trả về true vì trình biên dịch thực hiện quá tải toán tử - nó biết về * tại thời gian biên dịch *. Hãy thử '((đối tượng)" abc "). Bằng (moo)' để xem Hashtable sẽ làm gì. –

4

Vì vậy, các phôi tiềm ẩn không có liên quan. Họ sẽ không làm gì cả. Bạn sẽ nhận được kết quả tương tự nếu bạn nhận xét chúng. Điều quan trọng ở đây là các phương thức Equals và GetHashCode.

Vì vậy, phương pháp GetHashCode của bạn là tốt. Hai đối tượng (cho dù đó là một chuỗi hay một moo) sẽ luôn có cùng một giá trị băm nếu chúng giống nhau, vì vậy nó sẽ hoạt động. Vấn đề của bạn là với phương pháp equals của bạn.

moo.Equals("abc") sẽ trả về giá trị đúng.

object obj = moo; 
"abc".Equals(obj) 

sẽ trả về false; "abc".Equals(moo) sẽ trả về true chỉ vì có toán tử ngầm chuyển đổi moo thành chuỗi và sử dụng quá tải chuỗi Equals, thay vì quá tải đối tượng của Equals. Vì Hashtable sẽ lưu trữ mọi thứ dưới dạng đối tượng, nó sẽ luôn sử dụng quá tải object của phương thức Equals. (Toán tử == không được sử dụng, nó sử dụng phương thức Equals trong từ điển.) Điều này là do phương thức Equals của chuỗi sẽ kiểm tra để đảm bảo rằng đối tượng được truyền vào là một chuỗi và nó sẽ trả về false nếu không.

Giải pháp: Bạn không cần sử dụng hàm tạo mặc định của HashTable. Những gì bạn cần làm là sử dụng tùy chỉnh IEqualityComparor để nó không sử dụng phương thức Equals của chính đối tượng đó. Đây không phải là quá khó để làm. Chỉ cần tạo một lớp mới mở rộng IEqualityComparer và cung cấp cho nó phương thức equals cơ bản giống như phương thức Equals của moo của bạn để nó thực hiện so sánh đúng cách bất kể loại đối tượng nào.

+0

Không, "abc" .Equals (moo) trả về sự thật tôi sợ. – demoncodemonkey

+0

Sau đó, đó là do chuyển đổi tiềm ẩn, điều này sẽ không thể thực hiện được với một hashtable. 'object obj = moo; "abc" .Equals (obj) 'sẽ trả về false – Servy

+1

Tôi đã mở rộng câu trả lời để kết hợp một lời giải thích tốt hơn về những gì các cuộc gọi đến' Equals' đang làm. – Servy