我正在研究一种方法,它可以传入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>
<a href="1.php">All</a>
<a href="1.php?status=1">Status Active</a>
<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);
}
}
}
}
答案 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())
{
...
请注意,使用此方法,您也不需要dynamic
和ChangeType()
代码。
最后,您可能需要考虑更改不等式比较,以便不使用!=
运算符,而是使用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
还有很多额外的开销,最终它会回到执行相同的代码,我只是没有看到这样做的重点那样。)