Created
April 9, 2015 20:04
-
-
Save jeremybeavon/d8af10c21d09dad0b448 to your computer and use it in GitHub Desktop.
LINQ EqualityComparer Extensions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| namespace LinqEqualityComparerExtensions | |
| { | |
| public sealed class EqualityComparer<T> : IEqualityComparer<T> | |
| { | |
| private readonly Func<T, int> getHashCode; | |
| private readonly Func<T, T, bool> equals; | |
| public EqualityComparer(Func<T, int> getHashCode, Func<T, T, bool> equals) | |
| { | |
| if (getHashCode == null) | |
| { | |
| throw new ArgumentNullException("getHashCode"); | |
| } | |
| if (equals == null) | |
| { | |
| throw new ArgumentNullException("equals"); | |
| } | |
| this.getHashCode = getHashCode; | |
| this.equals = equals; | |
| } | |
| public int GetHashCode(T obj) | |
| { | |
| return getHashCode(obj); | |
| } | |
| public bool Equals(T x, T y) | |
| { | |
| return equals(x, y); | |
| } | |
| } | |
| public static class EnumerableExtensions | |
| { | |
| public static bool Contains<TSource>( | |
| this IEnumerable<TSource> source, | |
| TSource value, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Contains(value, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TSource> Distinct<TSource>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Distinct(new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TSource> Except<TSource>( | |
| this IEnumerable<TSource> first, | |
| IEnumerable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Except(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, IEnumerable<TElement>, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( | |
| this IEnumerable<TOuter> outer, | |
| IEnumerable<TInner> inner, | |
| Func<TOuter, TKey> outerKeySelector, | |
| Func<TInner, TKey> innerKeySelector, | |
| Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TSource> Intersect<TSource>( | |
| this IEnumerable<TSource> first, | |
| IEnumerable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Intersect(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>( | |
| this IEnumerable<TOuter> outer, | |
| IEnumerable<TInner> inner, | |
| Func<TOuter, TKey> outerKeySelector, | |
| Func<TInner, TKey> innerKeySelector, | |
| Func<TOuter, TInner, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static bool SequenceEqual<TSource>( | |
| this IEnumerable<TSource> first, | |
| IEnumerable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.SequenceEqual(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TSource> ToLookup<TSource, TKey>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>( | |
| this IEnumerable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IEnumerable<TSource> Union<TSource>( | |
| this IEnumerable<TSource> first, | |
| IEnumerable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Union(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| } | |
| public static class QueryableExtensions | |
| { | |
| public static bool Contains<TSource>( | |
| this IQueryable<TSource> source, | |
| TSource value, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Contains(value, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TSource> Distinct<TSource>( | |
| this IQueryable<TSource> source, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Distinct(new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TSource> Except<TSource>( | |
| this IQueryable<TSource> first, | |
| IQueryable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Except(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IQueryable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( | |
| this IQueryable<TSource> source, | |
| Expression<Func<TSource, TKey>> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IQueryable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( | |
| this IQueryable<TSource> source, | |
| Expression<Func<TSource, TKey>> keySelector, | |
| Expression<Func<TSource, TElement>> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TResult> GroupBy<TSource, TKey, TElement, TResult>( | |
| this IQueryable<TSource> source, | |
| Expression<Func<TSource, TKey>> keySelector, | |
| Expression<Func<TSource, TElement>> elementSelector, | |
| Expression<Func<TKey, IEnumerable<TElement>, TResult>> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( | |
| this IQueryable<TOuter> outer, | |
| IQueryable<TInner> inner, | |
| Expression<Func<TOuter, TKey>> outerKeySelector, | |
| Expression<Func<TInner, TKey>> innerKeySelector, | |
| Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TSource> Intersect<TSource>( | |
| this IQueryable<TSource> first, | |
| IQueryable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Intersect(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TResult> Join<TOuter, TInner, TKey, TResult>( | |
| this IQueryable<TOuter> outer, | |
| IQueryable<TInner> inner, | |
| Expression<Func<TOuter, TKey>> outerKeySelector, | |
| Expression<Func<TInner, TKey>> innerKeySelector, | |
| Expression<Func<TOuter, TInner, TResult>> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static bool SequenceEqual<TSource>( | |
| this IQueryable<TSource> first, | |
| IQueryable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.SequenceEqual(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( | |
| this IQueryable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>( | |
| this IQueryable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TSource> ToLookup<TSource, TKey>( | |
| this IQueryable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>( | |
| this IQueryable<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static IQueryable<TSource> Union<TSource>( | |
| this IQueryable<TSource> first, | |
| IQueryable<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Union(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| } | |
| public static class ParallelEnumerableExtensions | |
| { | |
| public static bool Contains<TSource>( | |
| this ParallelQuery<TSource> source, | |
| TSource value, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Contains(value, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TSource> Distinct<TSource>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return source.Distinct(new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TSource> Except<TSource>( | |
| this ParallelQuery<TSource> first, | |
| ParallelQuery<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Except(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TResult> GroupBy<TSource, TKey, TElement, TResult>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, IEnumerable<TElement>, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.GroupBy(keySelector, elementSelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( | |
| this ParallelQuery<TOuter> outer, | |
| ParallelQuery<TInner> inner, | |
| Func<TOuter, TKey> outerKeySelector, | |
| Func<TInner, TKey> innerKeySelector, | |
| Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TSource> Intersect<TSource>( | |
| this ParallelQuery<TSource> first, | |
| ParallelQuery<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Intersect(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TResult> Join<TOuter, TInner, TKey, TResult>( | |
| this ParallelQuery<TOuter> outer, | |
| ParallelQuery<TInner> inner, | |
| Func<TOuter, TKey> outerKeySelector, | |
| Func<TInner, TKey> innerKeySelector, | |
| Func<TOuter, TInner, TResult> resultSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static bool SequenceEqual<TSource>( | |
| this ParallelQuery<TSource> first, | |
| ParallelQuery<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.SequenceEqual(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToDictionary(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TSource> ToLookup<TSource, TKey>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>( | |
| this ParallelQuery<TSource> source, | |
| Func<TSource, TKey> keySelector, | |
| Func<TSource, TElement> elementSelector, | |
| Func<TKey, int> getHashCode, | |
| Func<TKey, TKey, bool> equals) | |
| { | |
| return source.ToLookup(keySelector, elementSelector, new EqualityComparer<TKey>(getHashCode, equals)); | |
| } | |
| public static ParallelQuery<TSource> Union<TSource>( | |
| this ParallelQuery<TSource> first, | |
| ParallelQuery<TSource> second, | |
| Func<TSource, int> getHashCode, | |
| Func<TSource, TSource, bool> equals) | |
| { | |
| return first.Union(second, new EqualityComparer<TSource>(getHashCode, equals)); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment