- Generic PropertyEqualityComparer<T>
- public sealed class PropertyEqualityComparer<T> : IEqualityComparer<T>
- {
- private readonly Type _iequatable = Type.GetType("System.IEquatable`1", false, true);
- private readonly PropertyInfo _property;
- public PropertyEqualityComparer(string property)
- {
- PropertyInfo propInfos = typeof(T).GetProperty(property);
- if (propInfos == null)
- {
- throw new ArgumentNullException();
- }
- // Ensure Property is Equatable (override of HashCode)
- if (propInfos.PropertyType.IsValueType
- || (!propInfos.PropertyType.IsValueType
- && propInfos.PropertyType.GetInterfaces().Any(type => type.Name == _iequatable.Name)))
- {
- _property = propInfos;
- }
- else
- {
- throw new ArgumentException();
- }
- }
- public bool Equals(T x, T y)
- {
- var xValue = _property.GetValue(x, null);
- var yValue = _property.GetValue(y, null);
- return xValue.Equals(yValue);
- }
- public int GetHashCode(T obj)
- {
- return _property.GetValue(obj, null).GetHashCode();
- }
- }
- public sealed class A
- {
- private string _s1;
- private B _b;
- public A(string s1, B b)
- {
- _s1 = s1;
- _b = b;
- }
- public string S1
- {
- get { return _s1; }
- set { _s1 = value; }
- }
- public B B
- {
- get { return _b; }
- set { _b = value; }
- }
- }
- public sealed class B : IEquatable<B>
- {
- private string _s;
- public string S
- {
- get { return _s; }
- set { _s = value; }
- }
- public B(string s)
- {
- S = s;
- }
- public override int GetHashCode()
- {
- return S.GetHashCode();
- }
- public override bool Equals(object obj)
- {
- return Equals(obj as B);
- }
- public bool Equals(B other)
- {
- return (other == null)
- ? false
- : this.S == other.S;
- }
- }
- B b = new B("baby");
- A[] __a = { new A("first", b), new A("second", b), new A("third", b)};
- PropertyEqualityComparer<A> aComparer = new PropertyEqualityComparer<A>("B");
- var vDistinct = __a.Distinct(aComparer).ToArray();
- // vDistinct = __a[0] { first, baby }
- var vContains = __a.Contains(new A("a", new B("baby")), aComparer);
- // True
- vContains = __a.Contains(new A("b", new B("foobar")), aComparer);
- // False
- var comparer = new ProjectionEqualityComparer<A, B>(a => a.B);
- // ...
- public sealed class ProjectionEqualityComparer<TSource, TKey>
- : EqualityComparer<TSource>
- {
- private readonly Func<TSource, TKey> _keySelector;
- private readonly IEqualityComparer<TKey> _keyComparer;
- public ProjectionEqualityComparer(Func<TSource, TKey> keySelector,
- IEqualityComparer<TKey> keyComparer = null)
- {
- if (keySelector == null)
- throw new ArgumentNullException("keySelector");
- _keySelector = keySelector;
- _keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
- }
- public override bool Equals(TSource x, TSource y)
- {
- if (x == null)
- return (y == null);
- if (y == null)
- return false;
- return _keyComparer.Equals(_keySelector(x), _keySelector(y));
- }
- public override int GetHashCode(TSource obj)
- {
- if (obj == null)
- throw new ArgumentNullException("obj");
- return _keyComparer.GetHashCode(_keySelector(obj));
- }
- }