【问题标题】:Method to Compare objects比较对象的方法
【发布时间】:2016-02-15 11:38:51
【问题描述】:

我正在研究一种可以传入 2 个相同类型的对象的方法,它将比较这两个对象。最后,我计划重载它以接受属性名称等,以仅评估那些或仅排除那些形成评估。在我完成基本的完整比较之后,这将不得不发生。

我已经能够比较值类型和引用类型。我被卡住的地方是能够比较可枚举的属性。 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();
}

【问题讨论】:

  • SequenceEqual 将不起作用,因为如果可枚举是具有集合属性的对象的集合,该怎么办。需要通过将列表中的每个对象传递给该对象来进行递归调用,然后该方法可以在其自己的迭代中对其进行评估。

标签: c# generics compare system.reflection


【解决方案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() 作为类型而不是 @987654332 @; 这可以让方法保持通用。但是dynamic 有很多额外的开销,最终它都会回到执行相同的代码,我只是不明白这样做的意义。)

【讨论】:

  • 好电话。我不得不承认,当我在手机上读到这篇文章时,我产生了怀疑。然后我回家后试了一下,效果很好。我什至可以保留动态类型。如果可以的话,当我开始构建它以完全按照我想要的方式进行时,我将改变它。 dynamic 类型和我相处不来。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
相关资源
最近更新 更多