Pass a lambda expression in place of IComparer or IEqualityComparer or any single-method interface?

后端 未结 8 1932
闹比i
闹比i 2020-12-08 08:57

I happened to have seen some code where this guy passed a lambda expression to a ArrayList.Sort(IComparer here) or a IEnumerable.SequenceEqual(IEnumerable list, IEqualityCom

相关标签:
8条回答
  • 2020-12-08 09:43

    I was also googling the web for a solution, but i didn't found any satisfying one. So i've created a generic EqualityComparerFactory:

    using System;
    using System.Collections.Generic;
    
    /// <summary>
    /// Utility class for creating <see cref="IEqualityComparer{T}"/> instances 
    /// from Lambda expressions.
    /// </summary>
    public static class EqualityComparerFactory
    {
        /// <summary>Creates the specified <see cref="IEqualityComparer{T}" />.</summary>
        /// <typeparam name="T">The type to compare.</typeparam>
        /// <param name="getHashCode">The get hash code delegate.</param>
        /// <param name="equals">The equals delegate.</param>
        /// <returns>An instance of <see cref="IEqualityComparer{T}" />.</returns>
        public static IEqualityComparer<T> Create<T>(
            Func<T, int> getHashCode,
            Func<T, T, bool> equals)
        {
            if (getHashCode == null)
            {
                throw new ArgumentNullException(nameof(getHashCode));
            }
    
            if (equals == null)
            {
                throw new ArgumentNullException(nameof(equals));
            }
    
            return new Comparer<T>(getHashCode, equals);
        }
    
        private class Comparer<T> : IEqualityComparer<T>
        {
            private readonly Func<T, int> _getHashCode;
            private readonly Func<T, T, bool> _equals;
    
            public Comparer(Func<T, int> getHashCode, Func<T, T, bool> equals)
            {
                _getHashCode = getHashCode;
                _equals = equals;
            }
    
            public bool Equals(T x, T y) => _equals(x, y);
    
            public int GetHashCode(T obj) => _getHashCode(obj);
        }
    }
    

    The idea is, that the CreateComparer method takes two arguments: a delegate to GetHashCode(T) and a delegate to Equals(T,T)

    Example:

    class Person
    {
        public int Id { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var list1 = new List<Person>(new[]{
                new Person { Id = 1, FirstName = "Walter", LastName = "White" },
                new Person { Id = 2, FirstName = "Jesse", LastName = "Pinkman" },
                new Person { Id = 3, FirstName = "Skyler", LastName = "White" },
                new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" },
            });
    
            var list2 = new List<Person>(new[]{
                new Person { Id = 1, FirstName = "Walter", LastName = "White" },
                new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" },
            });
    
    
            // We're comparing based on the Id property
            var comparer = EqualityComparerFactory.Create<Person>(
                a => a.Id.GetHashCode(),
                (a, b) => a.Id==b.Id);
            var intersection = list1.Intersect(list2, comparer).ToList();
        }
    }
    
    0 讨论(0)
  • 2020-12-08 09:45

    I'm not much sure what useful it really is, as I think for most cases in the Base Library expecting an IComparer there's an overload that expects a Comparison... but just for the record:

    in .Net 4.5 they've added a method to obtain an IComparer from a Comparison: Comparer.Create

    so you can pass your lambda to it and obtain an IComparer.

    0 讨论(0)
提交回复
热议问题