Is there a way to reduce amount of boilerplate code in Equals and GetHashCode?
c#, equals, gethashcode
Solution
I've done some research and found several components that were not quite what I wanted:
- EqualityComparer (nuget) - does not seem to provide meaningful `GetHashCode()` by default and too heavyweight to my taste.
- AnonymousComparer (nuget) - does not support `GetHashCode()` composition.
- MemberwiseEqualityComparer - requires adding custom attribute to exclude member from comparison this way it's not possible to flexibly configure comparisons for existing types. Personally doing `Emit` for this task is a little bit overkill.
- System.DataStructures.FuncComparer (nuget) - does not support composition.
And also a couple of related discussions:
- How to quickly check if two data transfer objects have equal properties in C#?
- Is there a better way to implment Equals for object with lots of fields?
So far idea of having explicitly configured list of members seemed unique. And I implemented my own library https://github.com/msugakov/YetAnotherEqualityComparer. It's better than the code suggested by TylerOhlsen in that it does not box extracted members and it uses `EqualityComparer<T>` to compare members.
Now the code looks like:
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);
}
}
Also the MemberEqualityComparer implements `IEqualityComparer<T>` and follows its semantics: it can successfully compare `default(T)` which may be `null` for reference types and Nullables.
UPDATE: There are tools that can solve the same problem of creating member based `IEqualityComparer<T>` but also these can provide composite `IComparer<T>`!
- Comparers (by Stephen Cleary) (nuget).
- ComparerExtensions (nuget).
Problem
I frequently have to override `Equals` and `GetHashCode` methods for the purpose of unit testing. After this my classes begin to look like this: ``` 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); } } ``` While it's not hard to do it, time after time it gets boring and error prone to maintain list of same fields in `Equals` and `GetHashCode`. Is there any way to list filelds used for equality checking and hash code function only once? Equals and GetHashCode should be implemented in terms of this setup list. In my imagination configuration and usage of such setup list may look like ``` 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); } } ``` There's a way to auto implement `hashCode` and `equals` in java, project lombok for example. I wonder is there anything serving the purpose of reducing boilerplate code readily available for C#.