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