2012-01-19 35 views
5

Tôi có một lớp với nhiều thuộc tính. Một bản sao nông là đủ để nhân rộng hoàn toàn đối tượng.So sánh hai thuộc tính của đối tượng đơn giản chỉ trong C#

Tôi cần so sánh một đối tượng chỉ để kiểm tra xem đối tượng có chứa chính xác các giá trị giống với một giá trị khác không.

ý tưởng của tôi:

Các giải pháp đầu tiên và rõ ràng nhất là chỉ để tạo ra một khối phương pháp khổng lồ so sánh mỗi tài sản, một sau khi khác.

Thứ hai, sẽ là sắp xếp từng đối tượng và băm tệp hoặc thực hiện một số loại kiểm tra md5 trên đó. (Điều này thực sự sẽ làm việc).

Thứ ba là thực hiện một số loại phản ánh trên đối tượng, điều này sẽ tự động hóa tùy chọn đầu tiên, nhưng tạo ra mức độ phức tạp cao hơn.

Tốc độ không thực sự là vấn đề.

Quan tâm đến việc nghe suy nghĩ hoặc bất kỳ phương pháp nào khác mà tôi thiếu để làm một việc như vậy.

Chỉnh sửa: Cảm ơn tất cả. Giải pháp của tôi: (Sửa đổi để bây giờ được đệ quy về các mục chung).

public static bool IsSame<T>(T objA, T objB) 
     { 
      var type = typeof(T); 
      var properties = type.GetProperties(); 
      foreach (var pi in properties.Where(a => a.CanRead)) 
      { 
       if (pi.Name == "Item") 
       { 
        var piCount = properties.FirstOrDefault(a => a.Name == "Count"); 
        int count = -1; 
        if (piCount != null && piCount.PropertyType == typeof(System.Int32)) 
         count = (int)piCount.GetValue(objA, null); 
        if (count > 0) 
        { 
         for (int i = 0; i < count; i++) 
         { 
          dynamic child1 = pi.GetValue(objA, new object[] { i }); 
          dynamic child2 = pi.GetValue(objB, new object[] { i }); 
          return IsSame(child1, child2); 
         } 
        } 
       } 
       else 
       { 
        var val1 = type.GetProperty(pi.Name).GetValue(objA, null); 
        var val2 = type.GetProperty(pi.Name).GetValue(objB, null); 
        if (val1 != val2 && (val1 == null || !val1.Equals(val2))) 
         return false; 
       } 
      } 
      return true; 
     } 
+2

tôi sẽ đi với sự phản chiếu trừ khi cấu trúc lớp học không dễ bị thay đổi. nếu nó * sẽ không * thay đổi, tôi sẽ chọn giải pháp đầu tiên thay thế (dễ đọc, dễ dàng để sử dụng) – Alex

+0

http://stackoverflow.com/questions/506096/comparing-object-properties-in-c-sharp there giải pháp sử dụng sự phản chiếu. – Giedrius

Trả lời

6

Hầu hết các bộ nối tiếp được thiết kế để đảm bảo dữ liệu duy trì tính toàn vẹn trong quá trình tuần tự hóa và deserialization, không tạo ra định dạng được tuần tự nhất quán. Tôi sẽ tránh sử dụng serialization cho mục đích này.

Bạn có thể xem xét triển khai IEquatable, để có từng trường hợp có khả năng so sánh chính nó với các phiên bản cùng loại. Hoặc một lớp học thực hiện các so sánh cho bạn thực hiện IEqualityComparer. Làm thế nào họ làm so sánh này có thể là 'phương pháp lớn' so sánh các thuộc tính sau cái khác, hoặc sử dụng sự phản chiếu.

Phản ánh có thể là một cách khá nhanh chóng và đơn giản để đạt được mục tiêu của bạn nhưng có thể gây ra sự cố (ví dụ: nếu ai đó thêm thuộc tính vào loại của bạn không được bao gồm để so sánh bình đẳng), cũng đúng (một người nào đó thêm một tài sản cần được kiểm tra bình đẳng, nhưng so sánh bình đẳng không được cập nhật). Cách tiếp cận nào bạn sử dụng nói chung nên được quyết định bởi mức độ thoải mái của nhóm đối với mỗi phương pháp tiếp cận song song với bối cảnh trong đó lớp học sẽ được sử dụng.

Trong trường hợp của bạn, tôi có thể khuyên bạn nên sử dụng phương pháp dựa trên phản xạ vì bạn muốn kiểm tra kết quả của một thao tác sao chép nông, vì vậy tất cả các thuộc tính phải bằng nhau.

Là một sang một bên, tôi khuyên bạn nên sử dụng phương pháp MemberwiseClone để tạo bản sao, điều này sẽ làm giảm nhu cầu cho các thử nghiệm nghiêm ngặt như vậy.

+3

Tôi nghĩ bạn muốn IEquatable hơn là IComparable. IComparable là để phân loại, không tương đương. –

+0

@ForgottenSemicolon Cảm ơn, câu trả lời đã được cập nhật. –

+0

+1 để đề xuất các giao diện tốt để xem xét triển khai. – pseudocoder

1

Một ý nghĩ khác là nếu các thuộc tính trả về các loại giá trị đơn giản, bạn có thể nhóm chúng thành các loại giá trị bất biến của riêng chúng. Ví dụ: nếu bạn có khách hàng có thuộc tính string Address1string Address2string Citystring Statestring Zip, bạn có thể tạo loại giá trị Địa chỉ thực hiện so sánh bình đẳng của chính nó và sử dụng nó.

Không chắc chắn nếu điều này áp dụng cho trường hợp của bạn, nhưng tôi thấy rằng khi tôi có một lớp học có nhiều tài sản, thường có thể làm điều này và nó có xu hướng làm cho lớp của tôi đơn giản và dễ dàng hơn trong khoảng.

6

Tùy chọn thứ ba (phản ánh) sẽ là chậm nhất, nhưng nó cũng sẽ là thử nghiệm/thử nghiệm mạnh nhất có thể.

Mã băm sẽ rất giống với tùy chọn đầu tiên, vì bạn sẽ phải gọi tất cả biến thành viên của mình, vì vậy 1 và 2 sẽ yêu cầu bạn cập nhật phương pháp .Equals(obj).GenerateHash() mỗi khi bạn sửa đổi danh sách biến thành viên của mình .

đây là một số mã để giúp bạn bắt đầu:

 foreach (FieldInfo field in this.GetType().GetFields()) 
     { 
      if (o[field.Name] == null) 
      { 
       if (!field.GetValue(this).Equals(o[field.Name])) 
        return false; 
      } 
      else 
      { 
       return false; 
      } 
     } 

     return true; 
1

Nếu bạn serialize bạn phải xác định thứ tự tuần tự trên mỗi Trường/tài sản để đảm bảo rằng tất cả các dữ liệu được serialized int theo thứ tự. Nhưng tất cả những gì bạn sẽ đạt được là triển khai GetHashCode() trong một lớp bên ngoài.

GetHashCode() có một số ví dụ về cách ghi đè, vì vậy hãy xem xét trước tiên.

Nếu lớp học của bạn có nhiều trường và bạn không muốn viết tất cả mã bằng tay. Bạn có thể sử dụng sự phản chiếu để tự động tạo mã. Nếu lớp của bạn thay đổi theo thời gian thì bạn có thể tạo một lớp một phần với việc thực hiện GetHashCode() trong một mẫu T4.

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