c#判断两个对象和对象中的属性是否相同(以及记录对象中的哪些字段,和详细的改变情况)
当前项目需要记录变更记录,即用户在进行编辑后,将变更操作记录下来。但是数据没有发生变化,则不记录。
代码1:(仅仅返回是否变化的标识)
/// <summary> /// 反射对比实体属性变更 /// </summary> /// <typeparam name="T"></typeparam> public class CompareEntry<T> { /// <summary> /// 编辑之前的对象和编辑后的对象进行对比 /// </summary> /// <returns></returns> public bool CompareDTO(T BeforeDTO, T AfterDTO) { bool IsEqual = true; if (BeforeDTO == null || AfterDTO == null) { IsEqual = false; } else if (BeforeDTO.Equals(DBNull.Value) || AfterDTO.Equals(DBNull.Value)) { IsEqual = false; }else if (BeforeDTO.GetType() != AfterDTO.GetType()) { IsEqual = false; return IsEqual; } else if (BeforeDTO is int || BeforeDTO is short || BeforeDTO is long || BeforeDTO is float || BeforeDTO is double || BeforeDTO is decimal) { //int 01与1 if (BeforeDTO is int) { if (Convert.ToInt32(BeforeDTO) != Convert.ToInt32(AfterDTO)) { IsEqual = false; } } else if (BeforeDTO is short) { if (Convert.ToInt16(BeforeDTO) != Convert.ToInt16(AfterDTO)) { IsEqual = false; } } else if (BeforeDTO is long) { if (Convert.ToInt64(BeforeDTO) != Convert.ToInt64(AfterDTO)) { IsEqual = false; } } else if (BeforeDTO is float) { if (Convert.ToSingle(BeforeDTO) != Convert.ToSingle(AfterDTO)) { IsEqual = false; } } else if (BeforeDTO is double) { if (Convert.ToDouble(BeforeDTO) != Convert.ToDouble(AfterDTO)) { IsEqual = false; } } else if (BeforeDTO is decimal) { if (Convert.ToDecimal(BeforeDTO) == Convert.ToDecimal(AfterDTO)) { IsEqual = false; } } } else { var beforeMembers = BeforeDTO.GetType().GetProperties(); var afterMembers = AfterDTO.GetType().GetProperties(); for (int i = 0; i < beforeMembers.Length; i++) { var beforeVal = beforeMembers[i].GetValue(BeforeDTO, null); var afterVal = afterMembers[i].GetValue(AfterDTO, null); var beforeValue = beforeVal == null ? null : beforeVal.ToString(); var afterValue = afterVal == null ? null : afterVal.ToString(); if (beforeValue != afterValue) { IsEqual = false; break; } } } return IsEqual; } }
调整后的代码:(返回标识以及详细变更记录)
/// <summary> /// /// </summary> public class CompareResult { /// <summary> /// /// </summary> public bool IsChange { get; set; } /// <summary> /// 变跟内容 /// </summary> public string ChangeContent { get; set; } } /// <summary> /// 对比实体属性变更(利用反射) /// </summary> public class CompareEntry { /// <summary> /// /// </summary> /// <returns></returns> public CompareResult CompareDTO(object BeforeDTO, object AfterDTO) { CompareResult result = new CompareResult(); bool b = false; if (BeforeDTO == null && AfterDTO != null) { b = true; } else if (BeforeDTO != null && AfterDTO == null) { b = true; } else if (BeforeDTO.Equals(DBNull.Value) && !AfterDTO.Equals(DBNull.Value)) { b = true; } else if (!BeforeDTO.Equals(DBNull.Value) && AfterDTO.Equals(DBNull.Value)) { b = true; } else if (BeforeDTO.GetType() != AfterDTO.GetType()) { result.IsChange = true; return result; } else if (BeforeDTO is int || BeforeDTO is short || BeforeDTO is long || BeforeDTO is float || BeforeDTO is double || BeforeDTO is decimal) { if (BeforeDTO is int) { if (Convert.ToInt32(BeforeDTO) != Convert.ToInt32(AfterDTO)) { b = true; } } else if (BeforeDTO is short) { if (Convert.ToInt16(BeforeDTO) != Convert.ToInt16(AfterDTO)) { b = true; } } else if (BeforeDTO is long) { if (Convert.ToInt64(BeforeDTO) != Convert.ToInt64(AfterDTO)) { b = true; } } else if (BeforeDTO is float) { if (Convert.ToSingle(BeforeDTO) != Convert.ToSingle(AfterDTO)) { b = true; } } else if (BeforeDTO is double) { if (Convert.ToDouble(BeforeDTO) != Convert.ToDouble(AfterDTO)) { b = true; } } else if (BeforeDTO is decimal) { if (Convert.ToDecimal(BeforeDTO) == Convert.ToDecimal(AfterDTO)) { b = true; } } } else { StringBuilder content = new StringBuilder(); var beforeMembers = BeforeDTO.GetType().GetProperties(); var afterMembers = AfterDTO.GetType().GetProperties(); for (int i = 0; i < beforeMembers.Length; i++) { var beforeVal = beforeMembers[i].GetValue(BeforeDTO, null); var afterVal = afterMembers[i].GetValue(AfterDTO, null); var beforeValue = beforeVal == null ? null : beforeVal.ToString(); var afterValue = afterVal == null ? null : afterVal.ToString(); if (beforeValue != afterValue) { b = true; content.Append(beforeMembers[i].Name+"("+ beforeValue+"->"+afterValue+")"); } } result.IsChange = b; result.ChangeContent = content.ToString(); } return result; } }
注意,引用类型进行对比的时候,需要在编辑之前对对象进行拷贝,让拷贝的对象与编辑后的对象进行对比。(因为引用类型不同于值类型,值类型每次操作都会产生一个新的对象,而引用类型在new一个新对象赋值时,其实是在堆上创建了一个内存地址,指向的仍然是原对象,对它操作原对象也会发生变化。所以只有通过拷贝复制一个新对象)