2011-07-12 27 views
11

Điều tôi đang cố gắng đạt được ở đây là so sánh giá trị thẳng của các loại nguyên thủy được đóng hộp.So sánh loại giá trị được đóng hộp

((object)12).Equals((object)12); // Type match will result in a value comparison, 
((object)12).Equals((object)12d); // but a type mismatch will not. (false) 
object.Equals((object)12,(object)12d); // Same here. (false) 

Tôi hiểu 'lý do'. Tôi chỉ không thấy 'làm sao'.

Các loại không xác định cho đến khi chạy, nơi chúng có thể là bất kỳ loại nguyên thủy nào từ nguồn dữ liệu. Điều đó bao gồm chuỗi, datetimes, bools, vv Tôi đã đi xuống con đường xấu xí của việc viết một phương pháp mở rộng mà làm việc ra cả hai loại, và sau đó phôi trước khi thực hiện một so sánh '==': (Đối với đầy đủ, tôi bao gồm tất cả nguyên thủy loại, cộng với những người tôi đã quan tâm đến)

public static bool ValueEquals(this object thisObj, object compare) 
    { 
     if (thisObj is int) 
     { 
      int obj = (int)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      if (compare is uint) 
       return (obj == (uint)compare); 
      if (compare is decimal) 
       return (obj == (decimal)compare); 
      if (compare is float) 
       return (obj == (float)compare); 
      <... and so on for each primitive type ...> 
     } 
     if (thisObj is uint) 
     { 
      uint obj = (uint)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      if (compare is uint) 
       return (obj == (uint)compare); 
      <... Again for each primitive type ...> 
     } 
     if (thisObj is decimal) 
     { 
      decimal obj = (decimal)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      <... Etc, etc ...> 

phương pháp kết quả hóa ra là dài 300 dòng, đó là tốt (chưa gớm ghiếc), nhưng bây giờ tôi cần phải làm nhiều hơn là chỉ '=='. Tôi cần>, <, < =,> =,! =.

Có điều gì trong Phản hồi mà tôi có thể sử dụng cho các so sánh loại giá trị được đóng hộp không?

Có gì không?

+0

Vì vậy, bạn chỉ muốn có thể so sánh hai giá trị được đóng hộp UNLIKE có thể chứa cùng một giá trị? Bạn không muốn Equals() vì hầu hết các so sánh không giống như các kiểu trả về false. Tôi muốn thử một cái gì đó như ... –

+0

Thay vào đó hãy sử dụng từ khóa * động * C# 4.0 *. –

+0

Tôi muốn tránh động vì bạn dễ bị các vấn đề thời gian chạy hơn. Với giải pháp dưới đây bạn ít nhất biết rằng cả hai loại đều có thể chuyển đổi tại thời gian biên dịch và tránh nhiều lỗi thời gian chạy. –

Trả lời

8

Có vẻ như bạn đang giả định loại từ arg1 là loại bạn muốn chuyển đổi thành, vì vậy tôi sẽ sử dụng một kiểu gen như thế này. Chừng nào arg2 là IConvertible (int, double, tất cả numerics, chuỗi, vv đều IConvertible) này sẽ làm việc:

public static bool ValueEquality<T1, T2>(T1 val1, T2 val2) 
    where T1 : IConvertible 
    where T2 : IConvertible 
{ 
    // convert val2 to type of val1. 
    T1 boxed2 = (T1) Convert.ChangeType(val2, typeof (T1)); 

    // compare now that same type. 
    return val1.Equals(boxed2); 
} 

** CẬP NHẬT ** Made cả hai loại args chung, đều có thể được suy ra và cho biết thêm hơn biên dịch an toàn thời gian trên arg2 để đảm bảo IConvertible tại thời gian biên dịch.

Với hàm tổng quát này, tất cả các nội dung sau giờ trở thành sự thật (không cần phải xác định loại tranh cãi kể từ khi suy ra từ số đầu tiên:

 Console.WriteLine(ValueEquality(1, "1")); 
     Console.WriteLine(ValueEquality(2, 2.0)); 
     Console.WriteLine(ValueEquality(3, 3L)); 

CẬP NHẬT

Dựa trên nhận xét của bạn, Đây là một tình trạng quá tải nếu tất cả những gì bạn có đều là các đối tượng, cả hai đều có thể tồn tại và nó sẽ gọi một cái phù hợp hơn dựa trên các đối số:

public static bool ValueEquality(object val1, object val2) 
    { 
     if (!(val1 is IConvertible)) throw new ArgumentException("val1 must be IConvertible type"); 
     if (!(val2 is IConvertible)) throw new ArgumentException("val2 must be IConvertible type"); 

     // convert val2 to type of val1. 
     var converted2 = Convert.ChangeType(val2, val1.GetType()); 

     // compare now that same type. 
     return val1.Equals(converted2); 
    } 

Và điều này sẽ làm việc cho đối tượng:

 object obj1 = 1; 
     object obj2 = 1.0; 

     Console.WriteLine(ValueEquality(obj1, obj2)); 

Như tôi đã nói, cả hai có thể cùng tồn tại như quá tải, vì vậy nếu bạn so sánh các loại IConvertible tương thích trực tiếp nó sẽ sử dụng chung, và nếu bạn chỉ có đóng hộp các loại như đối tượng, nó sẽ sử dụng quá tải đối tượng.

+0

Đáng buồn thay, tôi chỉ có các đối tượng để sử dụng làm đối số (các loại giá trị được đóng hộp). Điều này sẽ không làm việc cho tôi. – johnDisplayClass

+0

Cập nhật với tình trạng quá tải mới. Bạn có thể sử dụng cả hai và trình biên dịch sẽ chọn đúng một dựa trên rõ ràng IConvertible args hoặc đối tượng. –

+0

Lưu ý: Đặt 'val1' là int và' val2' dài hơn 'int.MaxValue'. Phương thức này sẽ ném một OverflowException thay vì trả về false, đó là ngữ nghĩa những gì tôi mong đợi sẽ xảy ra. – cdhowie

3

Xem xét sử dụng IComparable thay vì hướng dẫn sử dụng nếu - http://msdn.microsoft.com/en-us/library/system.icomparable.compareto.aspx.

Nếu bạn cần một cái gì đó tương tự trong tương lai, hãy xem xét về các loại toán hạng đầu tiên và thực hiện lớp "xử lý hoạt động" cho từng loại có phương pháp để xử lý thao tác như IntOpHandler.PerformOp(int left, object right).

Bạn cũng có thể giảm số lượng loại bạn cần xử lý bằng cách hợp nhất nhiều loại trước tiên (ví dụ: byte, ngắn, ushort, int, uint, long-cast to long first, sau đó thực hiện các thao tác dài).

+0

+1 để truyền sang loại tương tự. – johnDisplayClass

+0

Đây phải là câu trả lời. Câu hỏi đặt ra là sử dụng <, >, <= v.v. Và giao diện IComparable đang đưa ra câu trả lời cho điều này. – IgorStack

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