2013-03-19 8 views
6

मैंने अपने जैसे विभिन्न प्रश्न पढ़े हैं लेकिन उनमें से कोई भी मेरे मुद्दे को संबोधित नहीं करता है।IEquatable <T> लागू करें जब टी IENumerable <T>

मैं इस तरह एक प्रकार है:

class MyObject<T> : IEquatable<MyObject<T>> { // no generic constraints 
    private readonly string otherProp; 
    private readonly T value; 

    public MyObject(string otherProp, T value) 
    { 
    this.otherProp = otherProp; 
    this.value = value; 
    } 

    public string OtherProp { get { return this.otherProp; } } 

    public T Value { get { return this.value; } } 

    // ... 

    public bool Equals(MyObject<T> other) 
    { 
    if (other == null) 
    { 
     return false; 
    } 

    return this.OtherProp.Equals(other.OtherProp) && this.Value.Equals(other.Value); 
    } 
} 

जब T एक अदिश है MyObject<int> समानता ठीक से काम करता है, लेकिन जब मैं की तरह कुछ परिभाषित MyObject<IEnumerable<int>> समानता में विफल रहता है के रूप में।

कारण यह है कि जब टी IEnumerable<T> है तो मुझे this.Value.SequenceEqual(other.Value) पर कॉल करना चाहिए।

इस अंतर को संभालने के लिए Equals(MyObject<T>) बहुत सारे प्रकार के चेक और प्रतिबिंब (मेरे लिए, एसओएलआईडी/एसआरपी का उल्लंघन करने के कारण) के साथ।

मुझे एमएसडीएन दिशानिर्देशों में यह विशिष्ट मामला नहीं मिला, इसलिए यदि किसी को पहले से ही इस समस्या का सामना करना पड़ा है; यह ज्ञान बहुत अच्छा होगा अगर यह ज्ञान साझा किया जा सके।

संपादित करें: वैकल्पिक

K.I.S.S. के लिए, मैं कुछ इसी तरह करने के लिए सोच रहा हूँ:

class MyObject<T> : IEquatable<MyObject<T>> { 
    private readonly IEnumerable<T> value; 

    // remainder omitted 
} 

इस तरह Equal के कार्यान्वयन एक बहुत सरल हो जाएगा। और जब मुझे केवल एक मूल्य की आवश्यकता होती है तो मेरे पास 1 आइटम का संग्रह होता है। स्पष्ट रूप से टी एक संख्यात्मक नहीं होगा (लेकिन डेटा संरचना निजी है इसलिए कोई समस्या नहीं है)।

+0

यदि आपके मामले में यह संभव है, तो आप एक सामान्य बाधा भी जोड़ सकते हैं, जहां टी: IEquatable '। – Guillaume

+0

@ गुइलाउम, मुझे इसका मूल्यांकन करना और इसके बारे में तर्क करना है ... – jay

+0

संदर्भ के लिए मैं __Edit के तहत उत्तर में क्या जोड़ना चाहता हूं: वैकल्पिक__ मेरे असली समाधान के करीब था। मुझे लगता है कि 'IENumerable ' का उपयोग न करने के लिए कोई वैध कारण नहीं है, जब अधिकांश मामलों में 'टी' का संग्रह केवल एक तत्व होगा या खाली हो जाएगा। यह मामला नहीं है, संग्रह अक्सर एक से कुछ तत्वों से होता है; तो मैं कहूंगा कि 'माइक्रोनिएबल ' टाइप पैरामीटर के माध्यम से वैकल्पिक रूप से पारित होने के बजाय 'मायऑब्जेक्ट ' की परिभाषा में _hard coded_ होना चाहिए (मैं 'MyObject > 'से बचने की बात कर रहा हूं और इसके लिए जाना वैकल्पिक)। – jay

उत्तर

3

अपने MyObject<T> अपने प्रकार T के लिए एक समानता comparer लेने के लिए और उपयोग करते हैं:

class MyObject<T> : IEquatable<MyObject<T>> 
{ 
    private readonly IEqualityComparer<T> comparer; 
    public MyObject(string otherProp, T value, IEqualityComparer<T> comparer) 
    { 
     this.comparer = comparer; 
    } 
    public MyObject(string otherProp, T value) 
     : this(otherProp, value, EqualityComparer<T>.Default) 
    { 
    } 

    public bool Equals(MyObject<T> other) 
    { 
     return OtherProp.Equals(other.OtherProp) && comparer.Equals(this.Value, other.Value); 
    } 
} 

फिर IEnumerable<T> के लिए आप एक comparer जो दृश्यों तुलना उपयोग कर सकते हैं संदर्भों के बजाय।आप अपने ऑब्जेक्ट्स को बनाने के लिए कारखाने के तरीकों का उपयोग करना चाह सकते हैं ताकि यह सुनिश्चित किया जा सके कि समान तुलनात्मक प्रकार उसी T के लिए उपयोग किया जाता है ताकि समानता सममित सममित हो सके।

+0

+1, अच्छी तरह से लिखित कोड। बस इसे इंगित करने के लिए, यह 'int' जैसे प्रकारों के लिए स्वचालित रूप से काम करेगा (क्योंकि यह प्रश्न में उल्लिखित है)? – Default

+0

@ कन्स्ट्रक्टर इंजेक्शन 'के साथ आपूर्ति कारखाने के लिए @Lee +1; लेकिन जैसा कि एक और टिप्पणी में कहा गया है और मेरे नवीनतम संपादन में मैं बुनियादी ढांचा कोड लिखना टालना चाहता हूं। – jay

+0

@Lee, उत्तर के रूप में चिह्नित किया गया क्योंकि जैसा कि पिछली टिप्पणी में बताया गया है, मुझे सीआई का उपयोग पसंद आया। निर्भरता पारित करने के लिए। – jay

1

कोई प्रतिबिंब की आवश्यकता नहीं है। जाहिर है, उन संदर्भों को बराबर नहीं हो सकता है, जब TIEnumerable<T> है

IEnumerable e = other.Value as IEnumerable; 

if(e != null){ 
// use SequenceEqual 
}else{ 
// use Equals 
} 
+0

इस समाधान का प्रयास किया है, @alex? मुझे लगता है कि यहां प्रस्तुत इतना आसान नहीं है। 'अनुक्रम Equal' को एक प्रकार पैरामीटर की आवश्यकता है ताकि आपको' IENumerable 'पर डालना पड़े। अधिक कहने के लिए वर्तमान उदाहरण एक स्केलर या एक अलग टी के गणना योग्य हो सकता है। बहुत अधिक शामिल एक जांच करता है और मुझे नहीं लगता कि आप प्रतिबिंब छोड़ सकते हैं। इसमें अधिक शामिल है: 'स्ट्रिंग' को स्केलर के रूप में माना जाना चाहिए, लेकिन 'स्ट्रिंग' भी लागू होता है INumerable । – jay

+0

आप एक "सार्वभौमिक" समानता तुलनात्मक विधि लिख सकते हैं जो दो वस्तुओं को लेता है। यदि वे दोनों गिनती हैं, तो यह उन पर फिर से शुरू होता है। IENumerable की वस्तुओं की तुलना करने के लिए यह स्वयं को कॉल करता है। इसलिए सरणी की सरणी की तुलना सही ढंग से की जाएगी। आप प्रदर्शन अनुकूलन के रूप में स्ट्रिंग में कुछ अपवाद भी जोड़ सकते हैं। – alex

+0

क्षमा करें, लेकिन मैं चीजों को सरल रखना चाहता हूं। मैं बुनियादी ढांचे कोड के एक सामान्य टुकड़े को लिख और परीक्षण नहीं करूंगा। जैसा कि आप मेरे नवीनतम संपादन से प्रश्न में देख सकते हैं, मैं के.आई.एस.एस. उपाय। – jay

4

मामले में अपने कोड IEnumerable<T> के दो संदर्भों तुलना करता है और,: एक विकल्प की जाँच करने के लिए यदि मूल्य IEnumerable या अपने बराबर विधि में नहीं है। दरअसल, आपको यह व्यवहार मिल जाएगा, जब टी Equals विधि ओवरराइड किए बिना कोई संदर्भ प्रकार होगा।

यदि आप यहां संदर्भों की तुलना नहीं करना चाहते हैं, तो आपको एक कोड लिखना चाहिए, जो इन अनुक्रमों की उनकी सामग्री से तुलना करेगा। हालांकि, आपको ध्यान रखना चाहिए कि अनुक्रम अंतहीन हो सकता है।

+0

मैं शीर्षक संपादित करने वाला था ... लेकिन अब मैं देखता हूं कि मैंने इसे 'संरचनात्मक-समानता' के साथ सही तरीके से टैग किया है। – jay

1

यह वह मामला है जहां आपको सहायक वर्ग की मदद लेनी चाहिए, आपका MyObject प्रकार व्यक्तिगत समानता जांचकर्ता का उपयोग कर सकता है।

मैं कहूंगा कि स्थैतिक फैक्ट्री विधि के साथ एक रणनीति पैटर्न लागू करना आपके डिजाइन को सरल बना देगा।

कुछ की तरह आप हो सकता था

नीचे
class MyObject<T> : IEquatable<MyObject<T>> 
{ // no generic constraints 
    private readonly string otherProp; 
    private readonly T value; 

    public MyObject(string otherProp, T value) 
    { 
     this.otherProp = otherProp; 
     this.value = value; 
    } 

    public string OtherProp { get { return this.otherProp; } } 

    public T Value { get { return this.value; } } 

    // ... 

    public bool Equals(MyObject<T> other) 
    { 
     if (other == null) 
     { 
      return false; 
     } 

    var cheker = EqualityChekerCreator<T>.CreateEqualityChecker(other.Value); 

    if (cheker != null) 
     return cheker.CheckEquality(this.Value, other.value); 

     return this.OtherProp.Equals(other.OtherProp) && this.Value.Equals(other.Value); 
    } 
} 

public static class EqualityChekerCreator<T> 
{ 
    private static IEqualityCheker<T> checker; 

    public static IEqualityCheker<T> CreateEqualityChecker(T type) 
    { 
     var currenttype = type as IEnumerable<T>; 

     if(currenttype!=null) 
      checker = new SequenceEqualityChecker<T>(); 

     return checker; 
    } 
} 

public interface IEqualityCheker<in T> 
{ 
    bool CheckEquality(T t1, T t2); 
} 

public class SequenceEqualityChecker <T> : IEqualityCheker<T> 
{ 
    #region Implementation of IEqualityCheker<in T> 

    public bool CheckEquality(T t1, T t2) 
    { 
     // implement method here; 
    } 

    #endregion 
} 
संबंधित मुद्दे