C# 自动比较属性

C# 自动比较属性,c#,properties,comparison,C#,Properties,Comparison,我想获取为匹配对象更改的所有属性的名称。我有以下(简化)类: ChangedProperties应包含已更改属性的名称。我使用以下方法: //This structure represents the comparison of one member of an object to the corresponding member of another object. public struct MemberComparison { public stat

我想获取为匹配对象更改的所有属性的名称。我有以下(简化)类:


ChangedProperties
应包含已更改属性的名称。

我使用以下方法:

    //This structure represents the comparison of one member of an object to the corresponding member of another object.
    public struct MemberComparison
    {
        public static PropertyInfo NullProperty = null; //used for ROOT properties - i dont know their name only that they are changed

        public readonly MemberInfo Member; //Which member this Comparison compares
        public readonly object Value1, Value2;//The values of each object's respective member
        public MemberComparison(PropertyInfo member, object value1, object value2)
        {
            Member = member;
            Value1 = value1;
            Value2 = value2;
        }

        public override string ToString()
        { 
            return Member.name+ ": " + Value1.ToString() + (Value1.Equals(Value2) ? " == " : " != ") + Value2.ToString();
        }
    }

    //This method can be used to get a list of MemberComparison values that represent the fields and/or properties that differ between the two objects.
    public static List<MemberComparison> ReflectiveCompare<T>(T x, T y)
    {
        List<MemberComparison> list = new List<MemberComparison>();//The list to be returned

        if (x.GetType().IsArray)
        {
            Array xArray = x as Array;
            Array yArray = y as Array;
            if (xArray.Length != yArray.Length)
                list.Add(new MemberComparison(MemberComparison.NullProperty, "array", "array"));
            else
            {
                for (int i = 0; i < xArray.Length; i++)
                {
                    var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
                    if (compare.Count > 0)
                        list.AddRange(compare);
                }
            }
        }
        else
        {
            foreach (PropertyInfo m in x.GetType().GetProperties())
                //Only look at fields and properties.
                //This could be changed to include methods, but you'd have to get values to pass to the methods you want to compare
                if (!m.PropertyType.IsArray && (m.PropertyType == typeof(String) || m.PropertyType == typeof(double) || m.PropertyType == typeof(int) || m.PropertyType == typeof(uint) || m.PropertyType == typeof(float)))
                {
                    var xValue = m.GetValue(x, null);
                    var yValue = m.GetValue(y, null);
                    if (!object.Equals(yValue, xValue))//Add a new comparison to the list if the value of the member defined on 'x' isn't equal to the value of the member defined on 'y'.
                        list.Add(new MemberComparison(m, yValue, xValue));
                }
                else if (m.PropertyType.IsArray)
                {
                    Array xArray = m.GetValue(x, null) as Array;
                    Array yArray = m.GetValue(y, null) as Array;
                    if (xArray.Length != yArray.Length)
                        list.Add(new MemberComparison(m, "array", "array"));
                    else
                    {
                        for (int i = 0; i < xArray.Length; i++)
                        {
                            var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
                            if (compare.Count > 0)
                                list.AddRange(compare);
                        }
                    }
                }
                else if (m.PropertyType.IsClass)
                {
                    var xValue = m.GetValue(x, null);
                    var yValue = m.GetValue(y, null);
                    if ((xValue == null || yValue == null) && !(yValue == null && xValue == null))
                        list.Add(new MemberComparison(m, xValue, yValue));
                    else if (!(xValue == null || yValue == null))
                    {
                        var compare = ReflectiveCompare(m.GetValue(x, null), m.GetValue(y, null));
                        if (compare.Count > 0)
                            list.AddRange(compare);
                    }


                }
        }
        return list;
    }
//此结构表示对象的一个成员与另一个对象的相应成员之间的比较。
公共结构成员比较
{
public static PropertyInfo NullProperty=null;//用于根属性-我不知道它们的名称,只知道它们已更改
public readonly MemberInfo Member;//比较哪个成员
public readonly object Value1,Value2;//每个对象各自成员的值
公共成员比较(PropertyInfo成员、对象值1、对象值2)
{
成员=成员;
Value1=Value1;
Value2=Value2;
}
公共重写字符串ToString()
{ 
返回成员.name+“:”+Value1.ToString()+(Value1.Equals(Value2)?“==”:“!=”+Value2.ToString();
}
}
//此方法可用于获取MemberComparison值列表,这些值表示两个对象之间不同的字段和/或属性。
公共静态列表ReflectCompare(TX,TY)
{
List List=new List();//要返回的列表
if(x.GetType().IsArray)
{
数组xArray=x作为数组;
数组yArray=y作为数组;
if(xArray.Length!=yArray.Length)
添加(新的MemberComparison(MemberComparison.NullProperty,“array”,“array”);
其他的
{
for(int i=0;i0)
列表。添加范围(比较);
}
}
}
其他的
{
foreach(x.GetType().GetProperties()中的PropertyInfo m)
//只查看字段和属性。
//可以将其更改为包含方法,但必须获取传递给要比较的方法的值
如果(!m.PropertyType.IsArray&&(m.PropertyType==typeof(String)| | m.PropertyType==typeof(double)| | m.PropertyType==typeof(int)| | m.PropertyType==typeof(uint)| | m.PropertyType==typeof(float)))
{
var xValue=m.GetValue(x,null);
var yValue=m.GetValue(y,null);
if(!object.Equals(yValue,xValue))//如果在“x”上定义的成员的值不等于在“y”上定义的成员的值,则向列表中添加新的比较。
添加(新成员比较(m,yValue,xValue));
}
else if(m.PropertyType.IsArray)
{
数组xArray=m.GetValue(x,null)作为数组;
数组yArray=m.GetValue(y,null)作为数组;
if(xArray.Length!=yArray.Length)
添加(新成员比较(m,“数组”,“数组”));
其他的
{
for(int i=0;i0)
列表。添加范围(比较);
}
}
}
else if(m.PropertyType.IsClass)
{
var xValue=m.GetValue(x,null);
var yValue=m.GetValue(y,null);
if((xValue==null | | yValue==null)&&&!(yValue==null&&xValue==null))
添加(新成员比较(m、xValue、yValue));
else如果(!(xValue==null | | yValue==null))
{
var compare=ReflectiveCompare(m.GetValue(x,null),m.GetValue(y,null));
如果(compare.Count>0)
列表。添加范围(比较);
}
}
}
退货清单;
}

我们从两个简单的方法开始:

public bool AreEqual(object leftValue, object rightValue)
{
    var left = JsonConvert.SerializeObject(leftValue);
    var right = JsonConvert.SerializeObject(rightValue);

    return left == right;
}

public Difference<T> GetDifference<T>(T newItem, T oldItem)
{
    var properties = typeof(T).GetProperties();

    var propertyValues = properties
        .Select(p => new { 
            p.Name, 
            LeftValue = p.GetValue(newItem), 
            RightValue = p.GetValue(oldItem) 
        });

    var differences = propertyValues
        .Where(p => !AreEqual(p.LeftValue, p.RightValue))
        .Select(p => p.Name)
        .ToList();

    return new Difference<T>
    {
        ChangedProperties = differences,
        NewItem = newItem,
        OldItem = oldItem
    };
}
公共布尔值相等(对象leftValue、对象rightValue)
{
var left=JsonConvert.SerializeObject(leftValue);
var right=JsonConvert.SerializeObject(rightValue);
返回左==右;
}
公共差异GetDifference(T newItem,T oldItem)
{
var properties=typeof(T).GetProperties();
var propertyValues=属性
.Select(p=>new{
p、 名字,
LeftValue=p.GetValue(newItem),
RightValue=p.GetValue(旧项)
});
var差异=属性值
.式中(p=>!AreEqual(p.LeftValue,p.RightValue))
.Select(p=>p.Name)
.ToList();
返回新的差异
{
变更属性=差异,
NewItem=NewItem,
OldItem=OldItem
};
}
AreEqual只是使用Json.Net比较两个对象的序列化版本,这使它不会以不同的方式对待引用类型和值类型

GetDifference检查传入对象的属性并分别比较它们

要获取差异列表,请执行以下操作:

var oldPersonList = new List<Person> { 
    new Person { Name = "Bill" }, 
    new Person { Name = "Bob" }
};

var newPersonList = new List<Person> {
    new Person { Name = "Bill" },
    new Person { Name = "Bobby" }
};

var diffList = oldPersonList.Zip(newPersonList, GetDifference)
    .Where(d => d.ChangedProperties.Any())
    .ToList();
var oldPersonList=新列表{
新人{Name=“Bill”},
新人{Name=“Bob”}
};
var newPersonList=新列表{
新人{Name=“Bill”},
新人{Name=“Bobby”}
};
var diffList=oldPersonList.Zip(newPersonList,getdiffice)
.Where(d=>d.ChangedProperties.Any())
.ToList();

这里有一个代码,可以通过
反射实现您想要的功能

    public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP)
    {
        List<Difference> allDiffs = new List<Difference>();
        foreach (Person oldPerson in oldP)
        {
            foreach (Person newPerson in newP)
            {
                Difference curDiff = GetDifferencesTwoPersons(oldPerson, newPerson);
                allDiffs.Add(curDiff);
            }
        }

        return allDiffs;
    }

    private Difference GetDifferencesTwoPersons(Person OldPerson, Person NewPerson)
    {
        MemberInfo[] members = typeof(Person).GetMembers();

        Difference returnDiff = new Difference();
        returnDiff.NewPerson = NewPerson;
        returnDiff.OldPerson = OldPerson;
        returnDiff.ChangedProperties = new List<string>();
        foreach (MemberInfo member in members)
        {
            if (member.MemberType == MemberTypes.Property)
            {
                if (typeof(Person).GetProperty(member.Name).GetValue(NewPerson, null).ToString() != typeof(Person).GetProperty(member.Name).GetValue(OldPerson, null).ToString())
                {
                    returnDiff.ChangedProperties.Add(member.Name);
                }
            }
        }

        return returnDiff;
    }
public List GetDifferences(List oldP、List newP)
{
锂
public bool AreEqual(object leftValue, object rightValue)
{
    var left = JsonConvert.SerializeObject(leftValue);
    var right = JsonConvert.SerializeObject(rightValue);

    return left == right;
}

public Difference<T> GetDifference<T>(T newItem, T oldItem)
{
    var properties = typeof(T).GetProperties();

    var propertyValues = properties
        .Select(p => new { 
            p.Name, 
            LeftValue = p.GetValue(newItem), 
            RightValue = p.GetValue(oldItem) 
        });

    var differences = propertyValues
        .Where(p => !AreEqual(p.LeftValue, p.RightValue))
        .Select(p => p.Name)
        .ToList();

    return new Difference<T>
    {
        ChangedProperties = differences,
        NewItem = newItem,
        OldItem = oldItem
    };
}
var oldPersonList = new List<Person> { 
    new Person { Name = "Bill" }, 
    new Person { Name = "Bob" }
};

var newPersonList = new List<Person> {
    new Person { Name = "Bill" },
    new Person { Name = "Bobby" }
};

var diffList = oldPersonList.Zip(newPersonList, GetDifference)
    .Where(d => d.ChangedProperties.Any())
    .ToList();
    public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP)
    {
        List<Difference> allDiffs = new List<Difference>();
        foreach (Person oldPerson in oldP)
        {
            foreach (Person newPerson in newP)
            {
                Difference curDiff = GetDifferencesTwoPersons(oldPerson, newPerson);
                allDiffs.Add(curDiff);
            }
        }

        return allDiffs;
    }

    private Difference GetDifferencesTwoPersons(Person OldPerson, Person NewPerson)
    {
        MemberInfo[] members = typeof(Person).GetMembers();

        Difference returnDiff = new Difference();
        returnDiff.NewPerson = NewPerson;
        returnDiff.OldPerson = OldPerson;
        returnDiff.ChangedProperties = new List<string>();
        foreach (MemberInfo member in members)
        {
            if (member.MemberType == MemberTypes.Property)
            {
                if (typeof(Person).GetProperty(member.Name).GetValue(NewPerson, null).ToString() != typeof(Person).GetProperty(member.Name).GetValue(OldPerson, null).ToString())
                {
                    returnDiff.ChangedProperties.Add(member.Name);
                }
            }
        }

        return returnDiff;
    }
internal class PropertyComparer
{    
    public static IEnumerable<Difference<T>> GetDifferences<T>(PropertyComparer pc,
                                                               IEnumerable<T> oldPersons,
                                                               IEnumerable<T> newPersons)
        where T : Person
    {
        Dictionary<string, T> newPersonMap = newPersons.ToDictionary(p => p.Name, p => p);
        foreach (T op in oldPersons)
        {
            // match items from the two lists by the 'Name' property
            if (newPersonMap.ContainsKey(op.Name))
            {
                T np = newPersonMap[op.Name];
                Difference<T> diff = pc.SearchDifferences(op, np);
                if (diff != null)
                {
                    yield return diff;
                }
            }
        }
    }

    private Difference<T> SearchDifferences<T>(T obj1, T obj2)
    {
        CacheObject(obj1);
        CacheObject(obj2);
        return SimpleSearch(obj1, obj2);
    }

    private Difference<T> SimpleSearch<T>(T obj1, T obj2)
    {
        Difference<T> diff = new Difference<T>
                                {
                                    ChangedProperties = new List<string>(),
                                    OldPerson = obj1,
                                    NewPerson = obj2
                                };
        ObjectAccessor obj1Getter = ObjectAccessor.Create(obj1);
        ObjectAccessor obj2Getter = ObjectAccessor.Create(obj2);
        var propertyList = _propertyCache[obj1.GetType()];
        // find the common properties if types differ
        if (obj1.GetType() != obj2.GetType())
        {
            propertyList = propertyList.Intersect(_propertyCache[obj2.GetType()]).ToList();
        }
        foreach (string propName in propertyList)
        {
            // fetch the property value via the ObjectAccessor
            if (!obj1Getter[propName].Equals(obj2Getter[propName]))
            {
                diff.ChangedProperties.Add(propName);
            }
        }
        return diff.ChangedProperties.Count > 0 ? diff : null;
    }

    // cache for the expensive reflections calls
    private Dictionary<Type, List<string>> _propertyCache = new Dictionary<Type, List<string>>();
    private void CacheObject<T>(T obj)
    {
        if (!_propertyCache.ContainsKey(obj.GetType()))
        {
            _propertyCache[obj.GetType()] = new List<string>();
            _propertyCache[obj.GetType()].AddRange(obj.GetType().GetProperties().Select(pi => pi.Name));
        }
    }
}
PropertyComparer pc = new PropertyComparer();
var diffs = PropertyComparer.GetDifferences(pc, oldPersonList, newPersonList).ToList();
 virtual List<String> GetDifferences(Person otherPerson){
   var diffs = new List<string>();
   if(this.X != otherPerson.X) diffs.add("X");
   ....
 }