C# 使用反射比较对象属性

C# 使用反射比较对象属性,c#,asp.net,reflection,C#,Asp.net,Reflection,我有两个班,地址和员工如下: public class Address { public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } } publ

我有两个班,地址和员工如下:

 public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

   public class Employee
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public Address EmployeeAddress { get; set; }
    }
    var emp1Address = new Address();
    emp1Address.AddressLine1 = "Microsoft Corporation";
    emp1Address.AddressLine2 = "One Microsoft Way";
    emp1Address.City = "Redmond";
    emp1Address.State = "WA";
    emp1Address.Zip = "98052-6399";

    var emp1 = new Employee();
    emp1.FirstName = "Bill";
    emp1.LastName = "Gates";
    emp1.EmployeeAddress = emp1Address;


    var emp2Address = new Address();
    emp2Address.AddressLine1 = "Gates Foundation";
    emp2Address.AddressLine2 = "One Microsoft Way";
    emp2Address.City = "Redmond";
    emp2Address.State = "WA";
    emp2Address.Zip = "98052-6399";

    var emp2 = new Employee();
    emp2.FirstName = "Melinda";
    emp2.LastName = "Gates";
    emp2.EmployeeAddress = emp2Address;
我有两个员工实例,如下所示:

 public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

   public class Employee
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public Address EmployeeAddress { get; set; }
    }
    var emp1Address = new Address();
    emp1Address.AddressLine1 = "Microsoft Corporation";
    emp1Address.AddressLine2 = "One Microsoft Way";
    emp1Address.City = "Redmond";
    emp1Address.State = "WA";
    emp1Address.Zip = "98052-6399";

    var emp1 = new Employee();
    emp1.FirstName = "Bill";
    emp1.LastName = "Gates";
    emp1.EmployeeAddress = emp1Address;


    var emp2Address = new Address();
    emp2Address.AddressLine1 = "Gates Foundation";
    emp2Address.AddressLine2 = "One Microsoft Way";
    emp2Address.City = "Redmond";
    emp2Address.State = "WA";
    emp2Address.Zip = "98052-6399";

    var emp2 = new Employee();
    emp2.FirstName = "Melinda";
    emp2.LastName = "Gates";
    emp2.EmployeeAddress = emp2Address;

现在,我如何编写一个方法来比较这两个雇员并返回具有不同值的属性列表。因此,在本例中,我希望结果是FirstName和Address.AddressLine1。

执行比较不一定需要反射。您可以编写一个comparer类,该类接受两个Employee或Address实例,并比较应匹配的每个字段。对于任何不匹配的元素,您可以向某个列表添加一个字符串(或
PropertyInfo
)元素以返回给调用者

您是返回
属性信息
成员信息
,还是仅返回字符串,取决于调用者需要对结果执行什么操作。如果您确实需要访问包含差异的字段,则
PropertyInfo/MemberInfo
可能会更好,但如果只报告差异,字符串可能就足够了


反射的主要价值在于编写一个通用对象比较器,它可以获取任何类型对象的两个实例,并比较它们的公共字段和属性。这有助于避免一遍又一遍地编写重复的比较代码,但您的情况似乎并非如此。

正如LBushskin所说,您不必这样做。这不是最快的方法!如果您想购买,请尝试以下方法:

    public static List<PropertyInfo> GetDifferences(Employee test1, Employee test2)
    {
        List<PropertyInfo> differences = new List<PropertyInfo>();
        foreach (PropertyInfo property in test1.GetType().GetProperties())
        {
            object value1 = property.GetValue(test1, null);
            object value2 = property.GetValue(test2, null);
            if (!value1.Equals(value2))
            {
                differences.Add(property);
            }
        }
        return differences;
    }
公共静态列表GetDifferences(员工测试1、员工测试2)
{
列表差异=新列表();
foreach(test1.GetType().GetProperties()中的PropertyInfo属性)
{
objectvalue1=property.GetValue(test1,null);
objectvalue2=property.GetValue(test2,null);
如果(!value1.等于(value2))
{
差异。添加(属性);
}
}
回报差异;
}

无需反射。当然,这个示例返回一个带有属性名的字符串……如果您需要实际的
PropertyInfo
对象,事情会变得稍微困难一些,但不会太困难

public static IEnumerable<string> DiffEmployees
    (Employee one, Employee two)
{
    if(one.FirstName != two.FirstName)
        yield return "FirstName";
    if(one.LastName != two.LastName)
        yield return "LastName";
    if(one.Address.AddressLine1 != two.Address.AddressLine1)
        yield return "Address.AddressLine1";

    // And so on.
}
公共静态IEnumerable Differoyees
(一号员工、二号员工)
{
if(一个.FirstName!=两个.FirstName)
返回“FirstName”;
if(一个.LastName!=二个.LastName)
返回“LastName”;
if(one.Address.AddressLine1!=two.Address.AddressLine1)
返回“Address.AddressLine1”;
//等等。
}

这是一个基于奥斯卡·克杰林的通用递归解决方案

我也发布了这段代码,因此您可以查看最新版本或star/clone/fork-it:)

使用系统;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
受保护列表RecrusiveReflectionCompare(T第一,T第二)
T:在哪里上课
{
变量差异=新列表();
var parentType=first.GetType();
无效比较对象(对象obj1、对象obj2、属性信息)
{
如果(!obj1.等于(obj2))
{
添加(新的KeyValuePair(parentType,info));
}
}
foreach(parentType.GetProperties()中的PropertyInfo属性)
{
object value1=property.GetValue(第一个,null);
object value2=property.GetValue(第二个,null);
if(property.PropertyType==typeof(string))
{
if(string.IsNullOrEmpty(value1作为字符串)!=string.IsNullOrEmpty(value2作为字符串))
{
比较对象(值1、值2、属性);
}
}
else if(property.PropertyType.IsPrimitive)
{
比较对象(值1、值2、属性);
}
其他的
{
if(value1==null&&value2==null)
{
继续;
}
差异:Concat(RecursiveReflectionCompare(值1,值2));
}
}
回报差异;
}

为什么需要使用反射?这可能是一个很好的解决方案,但对于列表,如果容量参数不同,即使列表实体和计数相等,也不会产生正确的结果。如果将值2更改为null,则会导致null引用他特别要求使用反射的解决方案,而且,请避免按照您的建议手动操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

protected List<KeyValuePair<Type, PropertyInfo>> RecrusiveReflectionCompare<T>(T first, T second)
        where T : class
    {
        var differences = new List<KeyValuePair<Type, PropertyInfo>>();

        var parentType = first.GetType();

        void CompareObject(object obj1, object obj2, PropertyInfo info)
        {
            if (!obj1.Equals(obj2))
            {
                differences.Add(new KeyValuePair<Type, PropertyInfo>(parentType, info));
            }
        }

        foreach (PropertyInfo property in parentType.GetProperties())
        {
            object value1 = property.GetValue(first, null);
            object value2 = property.GetValue(second, null);

            if (property.PropertyType == typeof(string))
            {
                if (string.IsNullOrEmpty(value1 as string) != string.IsNullOrEmpty(value2 as string))
                {
                    CompareObject(value1, value2, property);
                }
            }
            else if (property.PropertyType.IsPrimitive)
            {
                CompareObject(value1, value2, property);
            }
            else
            {
                if (value1 == null && value2 == null)
                {
                    continue;
                }

                differences.Concat(RecrusiveReflectionCompare(value1, value2));
            }
        }
        return differences;
    }