一、创建CompareFieldAttribute标识要比较的字段

using System;

namespace CompareObjField
{
/// <summary>
/// 标识对象中要比较的属性
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class CompareFieldAttribute : Attribute
{
/// <summary>
/// 指定比较目标字段名称
/// </summary>
public string TargetFieldName { get; set; } /// <summary>
/// 所属数据库表名
/// </summary>
public string TableName { get; set; } /// <summary>
/// 如果目标对象不存在是否跳过
/// </summary>
public bool TargetNotExistsSkip { get; set; } /// <summary>
/// 在比较过程中0等于null或""
/// </summary>
public bool ZeroEqualNullOrEmpt { get; set; } /// <summary>
/// 初始化
/// </summary>
public CompareFieldAttribute()
{
TargetFieldName = "";
TableName = "";
TargetNotExistsSkip = false;
ZeroEqualNullOrEmpt = true;
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="targetFieldName">指定比较目标字段名称</param>
public CompareFieldAttribute(string targetFieldName)
{
TargetFieldName = targetFieldName;
} /// <summary>
/// 初始化
/// </summary>
/// <param name="targetFieldName">指定比较目标字段名称</param>
/// <param name="tableName">所属数据库表名</param>
/// <param name="targetNotExistsSkip"></param>
public CompareFieldAttribute(string targetFieldName="", string tableName="", bool targetNotExistsSkip=false)
{
TargetFieldName = targetFieldName;
TableName = tableName;
TargetNotExistsSkip = targetNotExistsSkip;
} }
}

二、比较操作类

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection; namespace CompareObjField
{
/// <summary>
/// 比较对象字段值公共类
/// </summary>
public static class CompareObj
{
/// <summary>
/// 比较两个对象中的指定字段值是否相等
/// </summary>
/// <typeparam name="TSource">要比较的类</typeparam>
/// <typeparam name="TTarget">原始数据类</typeparam>
/// <param name="source"></param>
/// <param name="target"></param>
/// <returns></returns>
public static List<DifferenceField> CompareObjFieldValue<TSource, TTarget>(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
List<DifferenceField> list = new List<DifferenceField>();
if (source == default(TSource))
{
throw new Exception("比较对象不能为空");
}
if (target == default(TTarget))
{
throw new Exception("被比较对象不能为空");
}
var sourceType = source.GetType();
var sourceCompareFields = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(t => t.GetCustomAttributes(typeof(CompareFieldAttribute), false).FirstOrDefault() != null).ToList();
var targetType = target.GetType();
var targetFields = targetType.GetProperties().ToList();
foreach (PropertyInfo property in sourceCompareFields)
{
var compareFieldAttribute = property.GetCustomAttributes(typeof(CompareFieldAttribute), false).FirstOrDefault(); if (compareFieldAttribute == null) continue;
var attributeFieldName = ((CompareFieldAttribute)compareFieldAttribute).TargetFieldName;
var attributeTableName = ((CompareFieldAttribute)compareFieldAttribute).TableName;
var targetFieldName = attributeFieldName != "" ? attributeFieldName : property.Name;
var sourceFielValue = property.GetValue(source) != null ? property.GetValue(source) : ""; var targetField = targetFields.FirstOrDefault(t => t.Name == targetFieldName); if (targetField == default(PropertyInfo))
{
if (((CompareFieldAttribute)compareFieldAttribute).TargetNotExistsSkip) continue;
throw new Exception(string.Format("比较出现异常,目标对象[{0}]不存在[{1}]字段", targetType.Name, targetFieldName));
}
var targetFieldValue = targetField.GetValue(target) != null ? targetField.GetValue(target).ToString() : "";
var describeAttr = property.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault();
var describeName = "";
if (describeAttr != null)
{
describeName = ((DisplayAttribute)describeAttr).Name;
}
try
{
if (sourceFielValue.ToString().Trim() == targetFieldValue.Trim()) continue; if (((CompareFieldAttribute)compareFieldAttribute).ZeroEqualNullOrEmpt)
{
if ((sourceFielValue.ToString() == "" || sourceFielValue.ToString() == "") && (targetFieldValue == "" || targetFieldValue == "")) continue;
} var isNullable = property.PropertyType.ToString().Contains("System.Nullable");
object sourceTypeValue = null; if (string.IsNullOrEmpty(sourceFielValue.ToString()))
{
sourceTypeValue = "";
}
else
{
if (isNullable)
{
sourceTypeValue = Convert.ChangeType(sourceFielValue, Nullable.GetUnderlyingType(property.PropertyType));
}
else
{
sourceTypeValue = Convert.ChangeType(sourceFielValue, property.PropertyType);
}
} object targetTypeValue = null;
if (string.IsNullOrEmpty(targetFieldValue))
{
if (sourceTypeValue.ToString().IsNumber())
{
targetFieldValue = "";
}
}
else
{
if (isNullable)
{
targetTypeValue = Convert.ChangeType(targetFieldValue, Nullable.GetUnderlyingType(property.PropertyType));
}
else
{
targetTypeValue = Convert.ChangeType(targetFieldValue, property.PropertyType);
}
}
if (targetTypeValue == null) targetTypeValue = ""; if (property.PropertyType != typeof(string) && sourceTypeValue.ToString().IsNumber() && targetTypeValue.IsNumber())
{
if (Math.Abs(Convert.ToDouble(sourceTypeValue) - Convert.ToDouble(targetTypeValue)) > )
{
list.Add(new DifferenceField() { SourceDescribe = describeName, SourceFiledName = property.Name, SourceValue = sourceFielValue, TargetValue = targetFieldValue, TableName = attributeTableName });
}
}
else if (sourceTypeValue.ToString().Trim() != targetTypeValue.ToString().Trim())
{
list.Add(new DifferenceField() { SourceDescribe = describeName, SourceFiledName = property.Name, SourceValue = sourceFielValue, TargetValue = targetFieldValue, TableName = attributeTableName });
}
}
catch (Exception)
{
list.Add(new DifferenceField() { SourceDescribe = describeName, SourceFiledName = property.Name, SourceValue = sourceFielValue, TargetValue = targetFieldValue, TableName = attributeTableName });
}
}
return list;
} /// <summary>
/// 判断字符串是否是数字
/// </summary>
/// <param name="num">数字字符串</param>
/// <returns></returns>
public static bool IsNumber(this object num)
{
try
{
Convert.ToDouble(num);
return true;
}
catch
{
return false;
}
} } /// <summary>
/// 比较结果差异对象
/// </summary>
public class DifferenceField
{
/// <summary>
/// 比较字段名称
/// </summary>
public string SourceDescribe { get; set; } /// <summary>
/// 比较字段
/// </summary>
public string SourceFiledName { get; set; } /// <summary>
/// 字段值
/// </summary>
public object SourceValue { get; set; } /// <summary>
/// 目标字段值
/// </summary>
public object TargetValue { get; set; } /// <summary>
/// 所属数据库表名
/// </summary>
public string TableName { get; set; }
} }

三、单元测试

1、定义测试类

using System;
using System.ComponentModel.DataAnnotations;
using CompareObjField; namespace UnitTestProject1
{
public class CompareClass
{
[Display(Name = "年龄")]
[CompareField(ZeroEqualNullOrEmpt = true)]
public int? Age { get; set; } [Display(Name = "数量")]
[CompareField(ZeroEqualNullOrEmpt = true)]
public decimal? Amount { get; set; } [Display(Name = "日期")]
[CompareField(ZeroEqualNullOrEmpt = true)]
public DateTime? DateTime { get; set; } [Display(Name = "名称")]
[CompareField]
public string FName { get; set; } [Display(Name = "身份证")]
[CompareField]
public string IDCard { get; set; }
} public class Class2
{
public int? Age { get; set; } public decimal? Amount { get; set; } public DateTime? DateTime { get; set; } public string FName { get; set; } public string IDCard { get; set; }
} }

2、单元测试

using System;
using CompareObjField;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json; namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
CompareClass c1 = new CompareClass() { Age = ,Amount = , FName = "19.00", IDCard = "" };
Class2 c2 = new Class2() { Age = , DateTime = DateTime.Now, Amount = , FName = "", IDCard = "" };
var res = CompareObj.CompareObjFieldValue(c1, c2);
Console.Write(JsonConvert.SerializeObject(res));
}
}
}

3、测试结果


测试结果中输出了所有差异字段的相关信息

四、附件下载地址

下载地址

C#比较两个对象中的指定字段值是否相等的更多相关文章

  1. mongodb 如何删除 字段值为 json对象中的某个字段值

    例如: { attributes: { birthday:'1988-01-01', name: 'aq' } } birthday是attributes字段的value的一个字段, 我要删除birt ...

  2. SQL查找TCar表中同一辆车前后两条记录的CarId,两条记录中有多个字段值一样

    查询同一个表中某一字段值相同的记录 select * from 表名 where 字段 in(select 字段 from 表名 group by 字段 having count(1)>1) s ...

  3. js对象中动态读取属性值 动态属性值 js正则表达式全局替换

    $(document).ready(function(){ var exceptionMsg = '${exception.message }'; var exceptionstr = ''; //j ...

  4. MySql存储过程批量删除多个数据库中同名表中的指定字段

    1. 创建存储过程batchDeleteField:删除所有名称为"MyDB_"开头的数据库中的指定字段 -- ---------------------------- -- Pr ...

  5. GridView控件RowDataBound事件中获取列字段值的几种途径

    前台: <asp:TemplateField HeaderText="充值总额|账号余额"> <ItemTemplate> <asp:Label ID ...

  6. 使用LINQ获取List列表中的某个字段值

    使用LINQ获取列表中的某个字段值,下面以获取员工列表中的编号字段为例子. 1.使用Select方法 List<Emplayee> emplayeeList = GetEmplayeeLi ...

  7. .NET中利用反射来实现自动映射两个对象中的数据成员

    在以前的项目开发之中,经常会遇到这样一个问题:比如在外面项目的架构设计之中,我们采用MVC和EntityFramework来构建一个Web应用程序.比如我们采用常用的多层架构,例如有Presentat ...

  8. Java中对比两个对象中属性值[反射、注解]

    在Java中通常要比较两个对象在修改前与修改后的值是否相同,一般我们采用的是反射技术获取对象的get方法[或其他的方法]获取值并做比较.如果系统将修改的属性名称也显示出来,这样就能更直观的显示类中的哪 ...

  9. java利用反射交换两个对象中的字段相同的字段值

    有时候我们的两个对象字段都是一样的,只有极少的区别,想要把一个对象字段的值,赋值给另外一个对象值 然后传给另外一个方法使用,但是这个字段太多,一个一个的复制太过繁琐. 这时候利用反射解决这个问题. c ...

随机推荐

  1. python del和垃圾回收

    1. del是删除对象 2. python中的垃圾回收是删除引用计数

  2. halcon 算子功能查找大全中文版(可直接下载)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543364.html haicon算子中文查找大全百度云链接 链接:https://pan. ...

  3. Thinkphp <= 5.0.10 缓存getshell复现

    目录 Thinkphp <= 5.0.10 缓存getshell复现 0x01 poc 0x02 跟踪源码 0x03 审计思路 0x04 补丁 0x05 参考 Thinkphp <= 5. ...

  4. ef实现一次查询多个聚合函数的字段

    想用ef来写一个统计字段的语句,如下所示 select sum(price) as price_total, sum(amount) as amount_total from table1 发现似乎实 ...

  5. ZooKeeper 面试题

    高强度训练第二十一天总结 1. ZooKeeper 面试题 ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群 中各个节点的状态根据节点提交的反馈进行下一步合理操作.最终 ...

  6. Object-C里的类目,延展,协议

    1.类目 类目就是为已存在的类添加新的方法.但是不能添加实例变量.比如系统的类,我们看不到他的.m文件,所以没有办法用直接添加方法的方式去实现. @interface NSMutableArray ( ...

  7. IT开发、PM、UI/UE学习路线图(非原创-参考传智播客网站介绍)

    文章大纲 一.Go语言+区块链学习路线图二.PHP学习路线图三.Python学习路线图四.C/C++学习路线图五.大数据学习路线图六.经理学习路线图七.UI/UE路线图八.参考文章 一.Go语言+区块 ...

  8. EXPDP导数报ORA-00942案例

    使用数据泵(expdp)导数时遇到了ORA-31626 & ORA-00942 错误,数据库版本为Oracle Database 10g Release 10.2.0.5.0,具体错误如下所示 ...

  9. InfluxDB因修改默认数据目录导致服务无法正常运行的问题(权限问题)

    在实际的生产中,考虑的实际情况,我们会调整一些默认配置,例如,数据目录.InfluxDB修改默认的Data目录后,因权限问题,服务无法正常运行.以下是具体的分析测试过程. 配置文件为 /etc/inf ...

  10. linux kernel下输入输出console如何实现【转】

    转自:https://blog.csdn.net/skyflying2012/article/details/41078349 最近工作在调试usb虚拟串口,让其作为kernel启动的调试串口,以及u ...