比较两个相同类型的实例是否相同, 支持忽略指定字段.

啊栈 .Net 421 次浏览 没有评论
//翠花, 上代码

var user1 = new User();
user1.Id = 1;
user1.Name = "翠花";
user1.Age = 18;

var user2 = new User();
user2.Id = 2;
user2.Name = "二狗";
user2.Age = 19;

//用法1
var isEq1 = ObjectUtil.Compare(user1, user2, x=> x.Id);

//用法2
var isEq2 = ObjectUtil.Compare(user1, user2, x=> new{ x.Id, x.Age });
public static class ObjectUtil
{
    /// <summary>
    /// 比较两个同类型的实例是否相同,
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="t1"></param>
    /// <param name="t2"></param>
    /// <param name="ignore">忽略不比较的字段, 可以传入单个字段, 也可以传入匿名类 x=>{ x.Id } </param>
    /// <returns></returns>
    public static bool Compare<TEntity>(TEntity t1, TEntity t2, Expression<Func<TEntity, object>> ignore)
    {
        /*
         * 优化方向: 缓存通过反射取得的属性.
         */

        //取所有属性, 只取有{get;set;}的属性哦.
        var properties = (typeof(TEntity)).GetProperties();

        //拆解传入的表达式
        var ignoreProperty = Extract(ignore);

        //判断忽略模式, 是单字段还是多字段. 下面判断会不一样
        var isManyIgnore = ignoreProperty.Contains(",");
        if (isManyIgnore)
        {
            //加个逗号做边界,增加比较精准度.
            ignoreProperty = $",{ignoreProperty},";
        }

        foreach (var property in properties)
        {
            var pName = property.Name;
            if (isManyIgnore && ignoreProperty.Contains($",{pName},"))
            {
                continue;
            }
            else
            {
                if (ignoreProperty == pName)
                {
                    continue;
                }
            }

            var v1 = GetPropertyValue(t1, property);
            var v2 = GetPropertyValue(t2, property);

            //只要有一对字段不相等. 就结束循环. 后面的不用比了.
            if (!v1.Equals(v2))
            {
                return false;
            }
        }

        return true;
    }

    #region 私有方法
    /*
     * 拆解表达式代码来自github项目52Chloe
     * 改造增加拆解匿名类表达式功能.
     * https://github.com/shuxinqin/Chloe/blob/481fcfd7ce260f7a31b0adde07311c5b25219829/src/Chloe/Entity/PropertyNameExtractor.cs
     */
    private static string Extract(Expression exp)
    {
        return Visit(exp);
    }
    private static string Visit(Expression exp)
    {
        switch (exp.NodeType)
        {
            case ExpressionType.Lambda:
                return VisitLambda((LambdaExpression)exp);
            case ExpressionType.MemberAccess:
                return VisitMemberAccess((MemberExpression)exp);
            case ExpressionType.Convert:
                return VisitUnary_Convert((UnaryExpression)exp);
            case ExpressionType.New:
                return VisitProperties(exp);
            default:
                throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
        }
    }
    private static string VisitLambda(LambdaExpression exp)
    {
        return Visit(exp.Body);
    }
    private static string VisitMemberAccess(MemberExpression exp)
    {
        return exp.Member.Name;
    }
    private static string VisitUnary_Convert(UnaryExpression exp)
    {
        return Visit(exp.Operand);
    }
    private static string VisitProperties(object exp)
    {
        var members = ((NewExpression)exp).Members;

        if (members == null || members.Count == 0)
        {
            return string.Empty;
        }

        return string.Join(",", members.Select(p => p.Name).ToArray());
    }
    private static object GetPropertyValue<T>(T t, PropertyInfo property)
    {
        return property.GetValue(t);
    }

    #endregion
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Go