比较对象的方法

时间:2015-11-13 19:27:32

标签: c# generics compare system.reflection

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

我已经能够比较值类型和引用类型。我被困的地方是能够比较Enumerable的属性。 <?php # Exercise solution 1 $employees = ''; $execute = array(); $options = array(0,1); $db = new PDO('mysql:host=localhost;dbname=eshop;charset=utf8', 'root', ''); $sql = "SELECT firstName,lastName FROM employees"; if(isset($_GET['status']) && in_array($_GET['status'], $options)){ $sql .= " WHERE status = ?"; $execute = array($_GET['status']); } $query = $db->prepare($sql); $query->setFetchMode(PDO::FETCH_OBJ); $query->execute($execute); $result = $query->fetchAll(); foreach($result as $row){ $employees .= "{$row->firstName} {$row->lastName}<br/>"; } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Exercise solution 1</title> </head> <body> <strong>Employees list</strong>&nbsp;&nbsp; <a href="1.php">All</a>&nbsp; <a href="1.php?status=1">Status Active</a>&nbsp; <a href="1.php?status=0">Status Not Active</a> <br/><br/> <div class="result-list"><?= $employees; ?></div> </body> </html> 语句是我无法正常工作的。

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);
                }
            }
        }
    }

1 个答案:

答案 0 :(得分: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()作为类型而不是{{ 1}};这可能允许该方法保持通用。但是property.PropertyType还有很多额外的开销,最终它会回到执行相同的代码,我只是没有看到这样做的重点那样。)