How to use the IEqualityComparer

前端 未结 6 1822
一向
一向 2020-11-27 04:36

I have some bells in my database with the same number. I want to get all of them without duplication. I created a compare class to do this work, but the execution of the fun

相关标签:
6条回答
  • 2020-11-27 04:55

    Just code, with implementation of GetHashCode and NULL validation:

    public class Class_reglementComparer : IEqualityComparer<Class_reglement>
    {
        public bool Equals(Class_reglement x, Class_reglement y)
        {
            if (x is null || y is null))
                return false;
    
            return x.Numf == y.Numf;
        }
    
        public int GetHashCode(Class_reglement product)
        {
            //Check whether the object is null 
            if (product is null) return 0;
    
            //Get hash code for the Numf field if it is not null. 
            int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();
    
            return hashNumf;
        }
    }
    

    Example: list of Class_reglement distinct by Numf

    List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
    
    0 讨论(0)
  • 2020-11-27 04:58

    Try This code:

    public class GenericCompare<T> : IEqualityComparer<T> where T : class
    {
        private Func<T, object> _expr { get; set; }
        public GenericCompare(Func<T, object> expr)
        {
            this._expr = expr;
        }
        public bool Equals(T x, T y)
        {
            var first = _expr.Invoke(x);
            var sec = _expr.Invoke(y);
            if (first != null && first.Equals(sec))
                return true;
            else
                return false;
        }
        public int GetHashCode(T obj)
        {
            return obj.GetHashCode();
        }
    }
    

    Example of its use would be

    collection = collection
        .Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
        .ToList(); 
    
    0 讨论(0)
  • 2020-11-27 04:59

    IEquatable<T> can be a much easier way to do this with modern frameworks.

    You get a nice simple bool Equals(T other) function and there's no messing around with casting or creating a separate class.

    public class Person : IEquatable<Person>
    {
        public Person(string name, string hometown)
        {
            this.Name = name;
            this.Hometown = hometown;
        }
    
        public string Name { get; set; }
        public string Hometown { get; set; }
    
        // can't get much simpler than this!
        public bool Equals(Person other)
        {
            return this.Name == other.Name && this.Hometown == other.Hometown;
        }
    
        public override int GetHashCode()
        {
            return Name.GetHashCode();  // see other links for hashcode guidance 
        }
    }
    

    Note you DO have to implement GetHashCode if using this in a dictionary or with something like Distinct.

    PS. I don't think any custom Equals methods work with entity framework directly on the database side (I think you know this because you do AsEnumerable) but this is a much simpler method to do a simple Equals for the general case.

    If things don't seem to be working (such as duplicate key errors when doing ToDictionary) put a breakpoint inside Equals to make sure it's being hit and make sure you have GetHashCode defined (with override keyword).

    0 讨论(0)
  • 2020-11-27 05:08

    The inclusion of your comparison class (or more specifically the AsEnumerable call you needed to use to get it to work) meant that the sorting logic went from being based on the database server to being on the database client (your application). This meant that your client now needs to retrieve and then process a larger number of records, which will always be less efficient that performing the lookup on the database where the approprate indexes can be used.

    You should try to develop a where clause that satisfies your requirements instead, see Using an IEqualityComparer with a LINQ to Entities Except clause for more details.

    0 讨论(0)
  • 2020-11-27 05:16

    Your GetHashCode implementation always returns the same value. Distinct relies on a good hash function to work efficiently because it internally builds a hash table.

    When implementing interfaces of classes it is important to read the documentation, to know which contract you’re supposed to implement.1

    In your code, the solution is to forward GetHashCode to Class_reglement.Numf.GetHashCode and implement it appropriately there.

    Apart from that, your Equals method is full of unnecessary code. It could be rewritten as follows (same semantics, ¼ of the code, more readable):

    public bool Equals(Class_reglement x, Class_reglement y)
    {
        return x.Numf == y.Numf;
    }
    

    Lastly, the ToList call is unnecessary and time-consuming: AddRange accepts any IEnumerable so conversion to a List isn’t required. AsEnumerable is also redundant here since processing the result in AddRange will cause this anyway.


    1 Writing code without knowing what it actually does is called cargo cult programming. It’s a surprisingly widespread practice. It fundamentally doesn’t work.

    0 讨论(0)
  • 2020-11-27 05:16

    If you want a generic solution without boxing:

    public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
    {
        private readonly Func<T, TKey> _keyGetter;
    
        public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
        {
            _keyGetter = keyGetter;
        }
    
        public bool Equals(T x, T y)
        {
            return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
        }
    
        public int GetHashCode(T obj)
        {
            TKey key = _keyGetter(obj);
    
            return key == null ? 0 : key.GetHashCode();
        }
    }
    
    public static class KeyBasedEqualityComparer<T>
    {
        public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
        {
            return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
        }
    }
    

    usage:

    KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)
    
    0 讨论(0)
提交回复
热议问题