IEqualityComparer का उपयोग कैसे करें


97

मेरे डेटाबेस में उसी नंबर के साथ कुछ घंटियाँ हैं। मैं उन सभी को नकल के बिना प्राप्त करना चाहता हूं। मैंने इस काम को करने के लिए एक तुलना वर्ग का निर्माण किया, लेकिन फ़ंक्शन के निष्पादन में फ़ंक्शन के बिना अलग-अलग देरी, 0.6 सेकंड से 3.2 सेकंड तक की देरी होती है!

क्या मैं इसे सही कर रहा हूं या मुझे दूसरी विधि का उपयोग करना है?

reg.AddRange(
    (from a in this.dataContext.reglements
     join b in this.dataContext.Clients on a.Id_client equals b.Id
     where a.date_v <= datefin && a.date_v >= datedeb
     where a.Id_client == b.Id
     orderby a.date_v descending 
     select new Class_reglement
     {
         nom  = b.Nom,
         code = b.code,
         Numf = a.Numf,
     })
    .AsEnumerable()
    .Distinct(new Compare())
    .ToList());

class Compare : IEqualityComparer<Class_reglement>
{
    public bool Equals(Class_reglement x, Class_reglement y)
    {
        if (x.Numf == y.Numf)
        {
            return true;
        }
        else { return false; }
    }
    public int GetHashCode(Class_reglement codeh)
    {
        return 0;
    }
}


यह ब्लॉग बताता है कि IEqualityComparer का पूरी तरह से उपयोग कैसे करें: blog.alex-turok.com/2013/03/c-linq-and-iequalitycomparer.html
जेरेमी रे ब्राउन

जवाबों:


173

आपका GetHashCodeकार्यान्वयन हमेशा समान मूल्य देता है। Distinctकुशलता से काम करने के लिए एक अच्छे हैश फ़ंक्शन पर निर्भर करता है क्योंकि यह आंतरिक रूप से एक हैश तालिका बनाता है ।

कक्षाओं के इंटरफेस को लागू करते समय प्रलेखन को पढ़ना महत्वपूर्ण है , यह जानने के लिए कि आपको किस अनुबंध को लागू करना है। 1

आपके कोड में, समाधान को अग्रेषित GetHashCodeकरना Class_reglement.Numf.GetHashCodeऔर इसे उचित रूप से लागू करना है।

इसके अलावा, आपका Equalsतरीका अनावश्यक कोड से भरा है। इसे निम्नानुसार लिखा जा सकता है (समान शब्दार्थ, कोड का itten, अधिक पठनीय):

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

अंत में, ToListकॉल अनावश्यक और समय लेने वाली है: AddRangeकिसी भी IEnumerableरूपांतरण को स्वीकार करने की Listआवश्यकता नहीं है। AsEnumerableहै भी परिणाम में प्रसंस्करण के बाद से यहां निरर्थक AddRangeइस वैसे भी कारण होगा।


1 यह जानने के बिना कोड लिखना कि कार्गो पंथ प्रोग्रामिंग कहा जाता है । यह आश्चर्यजनक रूप से व्यापक अभ्यास है। यह मूल रूप से काम नहीं करता है।


19
जब आपका x या y शून्य हो, तो आपकी समतुल्यता विफल हो जाती है।
दजेंद्रास

4
@dzendras उसी के लिए GetHashCode। हालाँकि, ध्यान दें कि दलीलों के साथ क्या करना है इसका दस्तावेज़ीकरणIEqualityComparer<T> निर्दिष्ट नहीं करता nullहै - लेकिन लेख में दिए गए उदाहरण nullया तो संभाल नहीं करते हैं।
कोनराड रुडोल्फ

49
वाह। घृणा अनावश्यक रूप से कठोर है। हम यहां एक-दूसरे की मदद करने के लिए हैं, अपमान करने के लिए नहीं। मुझे लगता है कि यह कुछ लोगों को हंसाता है, लेकिन मैं इसे हटाने की सिफारिश करूंगा।
जेस

4
+1 ने मुझे विकी पर "कार्गो पंथ प्रोग्रामिंग" के बारे में पढ़ने के लिए और फिर मेरी स्काइप टैग लाइन को "// डीप मैजिक यहां शुरू होता है ... कुछ भारी मैजोरी के बाद" के लिए पढ़ा।
एलेक्स

4
@NeilBenn आप अशिष्टता के लिए गलत सलाह की गलती करते हैं। जब से ओपी ने जवाब स्वीकार किया (और, मैं नोट कर सकता हूं, बहुत कठोर संस्करण में!), वे एक ही गलती नहीं करते थे। मुझे यकीन नहीं है कि आपको क्यों लगता है कि सलाह देना असभ्य है, लेकिन जब आप कहते हैं कि आपको गलत लगता है "आदमी को व्याख्यान की आवश्यकता नहीं है"। मैं दृढ़ता से असहमत हूं: व्याख्यान की आवश्यकता थी, और इसे दिल से लिया गया था। कोड, जैसा कि लिखा गया था, बुरा था, और बुरे कार्य अभ्यास पर आधारित था। यह इंगित नहीं करना एक असहमति होगी, और सभी सहायक नहीं, तब से ओपी में सुधार नहीं हो सकता है कि वे कैसे काम करते हैं।
कोनराड रुडोल्फ

47

इस कोड को आज़माएं:

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();
    }
}

इसके उपयोग का उदाहरण होगा

collection = collection
    .Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
    .ToList(); 

19
GetHashCodeअभिव्यक्ति का उपयोग करने की आवश्यकता है: इस पोस्ट को इसके उपयोग के लिए return _expr.Invoke(obj).GetHashCode();देखें ।
२१

3

बस कोड, कार्यान्वयन GetHashCodeऔर NULLसत्यापन के साथ:

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;
    }
}

उदाहरण: की सूची Class_reglement से अलग Numf

List<Class_reglement> items = items.Distinct(new Class_reglementComparer());

2

आपकी तुलना वर्ग (या विशेष रूप से AsEnumerableआपको इसे काम करने के लिए उपयोग करने के लिए जिस कॉल की आवश्यकता है) को शामिल करने का मतलब था कि सॉर्टिंग लॉजिक डेटाबेस सर्वर के आधार पर डेटाबेस क्लाइंट (आपके एप्लिकेशन) पर होने से चला गया। इसका मतलब था कि आपके क्लाइंट को अब बड़ी संख्या में रिकॉर्ड प्राप्त करने और फिर संसाधित करने की आवश्यकता है, जो हमेशा कम कुशल होगा जो डेटाबेस पर लुकअप का प्रदर्शन कर रहा है जहां एप्प्रोकेट इंडेक्स का उपयोग किया जा सकता है।

आपको एक ऐसा खंड विकसित करने का प्रयास करना चाहिए जो आपकी आवश्यकताओं को पूरा करता है, इसके बजाय अधिक विवरण के लिए IEQalityComparer का उपयोग LINQ से एंटिटीज के अलावा एक खंड के साथ देखें।


2

यदि आप बॉक्सिंग के बिना एक सामान्य समाधान चाहते हैं:

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);
    }
}

उपयोग:

KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)

0

IEquatable<T> आधुनिक रूपरेखाओं के साथ ऐसा करने का एक बहुत आसान तरीका हो सकता है।

आपको एक अच्छा सरल bool Equals(T other)कार्य मिलता है और कास्टिंग के साथ या अलग वर्ग बनाने में कोई गड़बड़ नहीं होती है।

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 
    }
}

ध्यान दें कि आपको GetHashCodeइसे डिक्शनरी में या किसी चीज़ के साथ प्रयोग करके लागू करना है Distinct

पुनश्च। मुझे नहीं लगता है कि कोई भी कस्टम बराबरी के तरीके डेटाबेस की तरफ से सीधे फ्रेमवर्क के साथ काम करते हैं (मुझे लगता है कि आप इसे जानते हैं क्योंकि आप असेंबल करते हैं) लेकिन सामान्य मामले के लिए एक साधारण समान करने के लिए यह बहुत सरल तरीका है।

यदि चीजें काम नहीं कर रही हैं (जैसे कि टोबो को करते समय डुप्लिकेट कुंजी की त्रुटियां) तो यह सुनिश्चित करने के लिए बराबर के अंदर एक ब्रेकपॉइंट डालें कि यह हिट हो रहा है और सुनिश्चित करें कि आपने GetHashCodeपरिभाषित किया है (ओवरराइड कीवर्ड के साथ)।


1
फिर भी आपको null
disklosr

मैं उसमें कभी नहीं भागा लेकिन मुझे अगली बार ऐसा करना याद होगा। क्या आपके पास सूची में एक अशक्त <टी> या ऐसा कुछ है?
साइमन_वेअर

1
जिस .Equals()विधि के तहत आप other.Hometownस्वयं की तुलना में दिखाई देते हैं , उसके बजायthis.Hometown
जेक स्टोक्स

उफ़। फिक्स्ड टाइपो :)
सिमोन_विवर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.