2015-11-13 136 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

良好的通话。我不得不承认,当我在手机上阅读这篇文章时,我有些怀疑。然后,当我回到家时,我尝试了它,它完美地工作。我甚至可以保持动态类型。如果可以的话,我将改变这一点,当我开始构建这个以完成我想要的事情时。 '动态'类型,我不相处。谢谢您的帮助! –