有没有办法减少 Equals 和 GetHashCode 中的样板代码量?

Mik*_*ike 5 c# equals gethashcode

为了进行单元测试,我经常必须重写Equals和方法。GetHashCode之后我的课程开始看起来像这样:

public class TestItem
{
    public bool BoolValue { get; set; }

    public DateTime DateTimeValue { get; set; }

    public double DoubleValue { get; set; }

    public long LongValue { get; set; }

    public string StringValue { get; set; }

    public SomeEnumType EnumValue { get; set; }

    public decimal? NullableDecimal { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as TestItem;

        if (other == null)
        {
            return false;
        }

        if (object.ReferenceEquals(this, other))
        {
            return true;
        }

        return this.BoolValue == other.BoolValue
            && this.DateTimeValue == other.DateTimeValue
            && this.DoubleValue == other.DoubleValue // that's not a good way, but it's ok for demo
            && this.EnumValue == other.EnumValue
            && this.LongValue == other.LongValue
            && this.StringValue == other.StringValue
            && this.EnumValue == other.EnumValue
            && this.NullableDecimal == other.NullableDecimal;
    }

    public override int GetHashCode()
    {
        return this.BoolValue.GetHashCode()
            ^ this.DateTimeValue.GetHashCode()
            ^ this.DoubleValue.GetHashCode()
            ^ this.EnumValue.GetHashCode()
            ^ this.LongValue.GetHashCode()
            ^ this.NullableDecimal.GetHashCode()
            ^ (this.StringValue != null ? this.StringValue.GetHashCode() : 0);
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然这并不难做到,但是一次又一次地维护Equals和中相同字段的列表会变得无聊并且容易出错GetHashCode。有没有办法只列出一次用于相等性检查和哈希码函数的fileld?Equals 和 GetHashCode 应该按照这个设置列表来实现。

在我的想象中,此类设置列表的配置和使用可能如下所示

public class TestItem
{
    // same properties as before

    private static readonly EqualityFieldsSetup Setup = new EqualityFieldsSetup<TestItem>()
        .Add(o => o.BoolValue)
        .Add(o => o.DateTimeValue)
        // ... and so on
        // or even .Add(o => o.SomeFunction())

    public override bool Equals(object obj)
    {
        return Setup.Equals(this, obj);
    }

    public override int GetHashCode()
    {
        return Setup.GetHashCode(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

有一种方法可以在java中自动实现,hashCode例如project lombok 。我想知道是否有任何东西可以减少 C# 可用的样板代码。equals

Mik*_*ike 2

我做了一些研究,发现几个组件并不完全是我想要的:

还有一些相关的讨论:

到目前为止,明确配置成员列表的想法似乎是独一无二的。我实现了自己的库https://github.com/msugakov/YetAnotherEqualityComparer。它比 TylerOhlsen 建议的代码更好,因为它不会对提取的成员进行装箱,而是用于EqualityComparer<T>比较成员。

现在代码如下所示:

public class TestItem
{
    private static readonly MemberEqualityComparer<TestItem> Comparer = new MemberEqualityComparer<TestItem>()
        .Add(o => o.BoolValue)
        .Add(o => o.DateTimeValue)
        .Add(o => o.DoubleValue) // IEqualityComparer<double> can (and should) be specified here
        .Add(o => o.EnumValue)
        .Add(o => o.LongValue)
        .Add(o => o.StringValue)
        .Add(o => o.NullableDecimal);

    // property list is the same

    public override bool Equals(object obj)
    {
        return Comparer.Equals(this, obj);
    }

    public override int GetHashCode()
    {
        return Comparer.GetHashCode(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,MemberEqualityComparer 实现IEqualityComparer<T>并遵循其语义:它可以成功比较default(T)引用null类型和 Nullables。

更新:有些工具可以解决基于创建成员的相同问题IEqualityComparer<T>,但这些工具也可以提供复合IComparer<T>