2015-11-13 140 views
2

我正在研究可以傳入2個相同類型對象的方法,它將比較這兩個對象。最後,我打算重載它以接受財產等名稱,只評估那些或僅排除那些形成評估。在完成基本的全面比較工作後,這將會發生。比較對象的方法

我已經能夠比較值類型和引用類型。我卡住的地方是能夠比較Enumerable的屬性。 else聲明是我無法正常工作的聲明。

public static void CompareObjects<T>(T obj1, T obj2) 
{ 
    foreach (var property in typeof(T).GetProperties()) 
    { 
     var obj1Prop = property.GetValue(obj1); 
     var obj2Prop = property.GetValue(obj2); 

     //for value types 
     if (property.PropertyType.IsPrimitive || property.PropertyType.IsValueType || property.PropertyType == typeof(string)) 
     { 
      if (obj1Prop != obj2Prop) 
       Console.WriteLine($"Object 1 {property.Name}:{obj1Prop}{Environment.NewLine}Object 2 {property.Name}:{obj2Prop}{Environment.NewLine}"); 
      } 
      //for objects 
      else if (property.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) 
      { 
       dynamic obj1PropObj = Convert.ChangeType(obj1Prop, property.PropertyType); 
       dynamic obj2PropObj = Convert.ChangeType(obj2Prop, property.PropertyType); 
       CompareObjects(obj1PropObj, obj2PropObj); 
      } 
      //for Enumerables 
      else 
      { 
       var enumerablePropObj1 = property.GetValue(obj1) as IEnumerable; 
       var enumerablePropObj2 = property.GetValue(obj2) as IEnumerable; 

       if (enumerablePropObj1 == null) continue; 
       if (enumerablePropObj2 == null) continue; 

       var list1 = enumerablePropObj1.GetEnumerator(); 
       var list2 = enumerablePropObj2.GetEnumerator(); 

       while (list1.MoveNext()) 
       { 
        list2.MoveNext(); 
        CompareObjects(list1.Current, list2.Current); 
       } 
      } 
     } 
    } 

這遍歷整個列表,但沒有值。我用來實現此設置如下:

static void Main(string[] args) 
{ 
    var student1 = new Student 
    { 
     FirstName = "John", 
     LastName = "Smith", 
     Age = 18, 
     DateOfBirth = DateTime.Parse("1989/03/03"), 
     Job = new Job 
     { 
      Company = "CompanyOne", 
      Title = "Supervisor" 
     }, 
     PhoneNumbers = new List<PhoneNumber> 
     { 
      new PhoneNumber 
      { 
       Number = "8675309", 
       Label = "Home" 
      }, 
      new PhoneNumber 
      { 
       Number = "1234567", 
       Label = "Work" 
      } 
     } 
    }; 
    var student2 = new Student 
    { 
     FirstName = "Theodore", 
     LastName = "Smith", 
     Age = 22, 
     DateOfBirth = DateTime.Parse("1990/03/03"), 
     Job = new Job 
     { 
      Company = "CompanyOne", 
      Title = "Manager" 
     }, 
     PhoneNumbers = new List<PhoneNumber> 
     { 
      new PhoneNumber 
      { 
       Number = "8675308", 
       Label = "Home" 
      }, 
      new PhoneNumber 
      { 
       Number = "1234567", 
       Label = "Work" 
      } 
     } 
    }; 

    CompareObjects(student1, student2); 
    Console.WriteLine("Done"); 

    Console.ReadKey(); 
} 
+0

[is-a-built -in-method-to-compare-collections-in-c#](http://stackoverflow.com/q/43500/463206) – radarbob

+0

SequenceEqual不會工作,因爲如果t他enumerable是具有集合屬性的對象的集合。遞歸調用需要通過將列表中的每個對象傳遞給該對象,然後由該方法在其自己的迭代中進行評估。 –

回答

1

您的問題是,您的方法是通用的。當您在子集上調用它時,用於比較的類型是System.Object,這當然沒有比較有趣的屬性。

改變你的方法聲明和方法的序言:

public static void CompareObjects(object obj1, object obj2) 
{ 
    if (obj1.GetType() != obj2.GetType()) 
    { 
     return; 
    } 

    foreach (var property in obj1.GetType().GetProperties()) 
    { 
     ... 

注意,使用這種方法,你也並不需要dynamicChangeType()代碼。

最後,你可能要考慮改變你的不平等相比,這樣的而不是使用!=操作它使用Equals()方法:

 if (!obj1Prop.Equals(obj2Prop)) 
     { 
      Console.WriteLine($"Object 1 {property.Name}:{obj1Prop}{Environment.NewLine}Object 2 {property.Name}:{obj2Prop}{Environment.NewLine}"); 
     } 

即使方法是通用的,這將是一個不錯的主意;而一個是假設實施等於和不平等運營商,如果一個覆蓋Equals(),這並不總是發生。當方法是非泛型的,當然你甚至不會爲特定類型獲得運算符重載(至少不是沒有額外的工作)。


(我想你可以代替上述使用您使用用於非枚舉的屬性相同的dynamic/ChangeType()的方法,使用例如list1.Current.GetType()作爲類型代替property.PropertyType;可能允許該方法保持通用。但是dynamic有很多額外的開銷,最終它會回落到執行相同的代碼,我只是沒有看到這樣做的重點。)

+0

良好的通話。我不得不承認,當我在手機上閱讀這篇文章時,我有些懷疑。然後,當我回到家時,我嘗試了它,它完美地工作。我甚至可以保持動態類型。如果可以的話,我將改變這一點,當我開始構建這個以完成我想要的事情時。 '動態'類型,我不相處。謝謝您的幫助! –