Skip to content

Instantly share code, notes, and snippets.

@Steinblock
Created November 4, 2015 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Steinblock/f454d2dd04bd6d0d5b4a to your computer and use it in GitHub Desktop.
Save Steinblock/f454d2dd04bd6d0d5b4a to your computer and use it in GitHub Desktop.
GenericEqualityComparer
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Utils
{
public class GenericEqualityComparer<T> : EqualityComparer<T>
{
public GenericEqualityComparer(Func<T, int> getHashCode)
{
this.getHashCode = getHashCode;
}
public GenericEqualityComparer() : this(x => x.GetHashCode()) { }
public GenericEqualityComparer(Expression<Func<T, Object>> expression) : this(Build(expression)) { }
private static Func<T, int> Build(Expression<Func<T, Object>> expression)
{
var execute = expression.Compile();
return x =>
{
var result = execute(x);
if (result == null) throw new ArgumentNullException();
return result.GetHashCode();
};
}
private Func<T, int> getHashCode;
public override bool Equals(T x, T y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return GetHashCode(x).Equals(GetHashCode(y));
}
public override int GetHashCode(T obj)
{
if (obj == null) throw new ArgumentNullException();
return getHashCode(obj);
}
}
[TestClass]
public class GenericEqualityComparerTest
{
private class Product
{
public string Name { get; set; }
public string ProductNo { get; set; }
}
[TestMethod]
public void TestComparer()
{
var a = new Product { Name = "Test", ProductNo = "123", };
var b = new Product { Name = "Test", ProductNo = "123", };
var c = new Product { Name = "Test", ProductNo = "456", };
// Default, same as a.Equals(b) with null check;
var comparerA = new GenericEqualityComparer<Product>();
Assert.IsFalse(comparerA.Equals(a, b));
Assert.IsFalse(comparerA.Equals(b, c));
// Compare by single property
var comparerB = new GenericEqualityComparer<Product>(x => x.Name);
Assert.IsTrue(comparerB.Equals(a, b));
Assert.IsTrue(comparerB.Equals(b, c));
// Compare by multiple properties
var comparerC = new GenericEqualityComparer<Product>(x => new { x.Name, x.ProductNo });
Assert.IsTrue(comparerC.Equals(a, b));
Assert.IsFalse(comparerC.Equals(b, c));
// Custom implementation
var comparerD = new GenericEqualityComparer<Product>(x => x.Name.GetHashCode());
Assert.IsTrue(comparerD.Equals(a, b));
Assert.IsTrue(comparerD.Equals(b, c));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment