C#比较两个对象中的指定字段值是否相等

一、创建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() == "0") && (targetFieldValue == "" || targetFieldValue == "0")) 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 = "0";
                        }
                    }
                    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)) > 0)
                        {
                            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 = 1,Amount = 19, FName = "19.00", IDCard = "513709199310151835" };
            Class2 c2 = new Class2() { Age = 3, DateTime = DateTime.Now, Amount = 18, FName = "19", IDCard = "513709199310151836" };
            var res = CompareObj.CompareObjFieldValue(c1, c2);
            Console.Write(JsonConvert.SerializeObject(res));
        }
    }
}

3、测试结果


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

四、附件下载地址

下载地址

猜你喜欢

转载自www.cnblogs.com/zjbky/p/9242401.html