首页 > 解决方案 > 如何强制向 IEquatable 的 Equals 方法添加新的公共属性班级

问题描述

我有包含其他子类的类,所以我已经实现了以递归IEquatable<T>方式执行自定义方法。Equals这工作正常,但我在想如果其他开发人员需要向这些类添加新的公共属性,我们希望强制他们也将它们添加到Equals方法中。我想知道是否有一种简单的方法可以在没有反射的情况下做到这一点?我可以以某种方式利用自定义属性吗?我基本上想将它添加到单元测试套件中,这样构建就会失败。

标签: c#unit-testingasp.net-coreiequatable

解决方案


如果您想强制您的相等方法以标准方式构建,也许您可​​以在运行时使用反射编译它们;

    private static Expression Equality(Type propType, MemberExpression thisProp, MemberExpression otherProp)
    {
        var equatable = typeof(IEquatable<>).MakeGenericType(propType);
        var equal = Expression.Equal(thisProp, otherProp);

        if (!equatable.IsAssignableFrom(propType))
            return equal;

        // a == b || (a!=null && a.Equals(b))
        return Expression.OrElse(
            equal, 
            Expression.AndAlso(
                Expression.NotEqual(thisProp, Expression.Constant(null, propType)),
                Expression.Call(thisProp, equatable.GetMethod("Equals"), otherProp)
            )
        );
    }

    private static Delegate GenerateEquatable(Type type)
    {
        var thisParm = Expression.Parameter(type, "a");
        var otherParm = Expression.Parameter(type, "b");
        return Expression.Lambda(
            type.GetProperties()
                .Where(prop => prop.CanRead)
                .Select(prop => Equality(
                    prop.PropertyType,
                    Expression.MakeMemberAccess(thisParm, prop),
                    Expression.MakeMemberAccess(otherParm, prop)))
                .Aggregate((a, b) => Expression.AndAlso(a, b)),
            thisParm, otherParm).Compile();
    }

    public static Func<T, T, bool> GenerateEquatable<T>() where T:IEquatable<T> =>
        (Func<T, T, bool>)GenerateEquatable(typeof(T));

    public class Foo : IEquatable<Foo>{
        private static Func<Foo, Foo, bool> _equals = GenerateEquatable<Foo>();
        public bool Equals([AllowNull] Foo other) => other != null && _equals(this, other);
    }


推荐阅读