2011-08-13 7 views
10

यह मैं क्या करने की कोशिश कर रहा है के बारे में एक उदाहरण है:मैं इस कोड को कैसे बेहतर बना सकते हैं: विरासत और IEquatable <>

public class Foo : IEquatable<Foo> 
{ 
    public bool Equals(Foo other) 
    { 
     Type type1 = this.GetType(); 
     Type type2 = other.GetType(); 

     if (type1 != type2) 
      return false; 

     if (type1 == typeof(A)) 
     { 
      A a = (A)this; 
      A b = (A)other; 

      return a.Equals(b); 
     } 
     else if (type1 == typeof(B)) 
     { 
      B c = (B)this; 
      B d = (B)other; 

      return c.Equals(d); 
     } 
     else 
     { 
      throw new Exception("Something is wrong"); 
     } 
    } 
} 

public class A : Foo, IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public bool Equals(A other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2; 
    } 
} 

public class B : Foo, IEquatable<B> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 
    public int Number3 { get; set; } 

    public bool Equals(B other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2 && this.Number3 == other.Number3; 
    } 
} 

लेकिन जैसा कि आप ऊपर देख सकते हैं, मैं कई सशर्त, उपयोग करने के लिए होगा वास्तविक प्रकार की पहचान करने के लिए 'अगर'। समस्या यह है कि मुझे बेस क्लास का उपयोग करना है। उदाहरण के लिए:

A a = new A(); 
Foo foo = a; 

foo.Equals(another); 
+0

आपको पहली जगह 'IEquatable ' क्यों चाहिए? यह यहां कोई मूल्य नहीं जोड़ रहा है। बस सुनिश्चित करें कि subtypes (समझदारी से) 'ऑब्जेक्ट। GetHashCode' और 'object.Equals (ऑब्जेक्ट)' को ओवरराइड करें, मौजूदा' IEquatable 'कार्यान्वयन के अतिरिक्त। फिर आपको मुफ्त में आभासी विधि प्रेषण मिलता है, और यह कई और स्थितियों में काम करेगा। – Ani

+0

@ एनी क्या आप मुझे एक उदाहरण दिखाएंगे? –

+0

हम्म। ये कक्षाएं अजीब लगती हैं। फू का उद्देश्य क्या है क्योंकि इसमें कोई गुण नहीं है? इसके अलावा यदि बी सिर्फ एक नंबर के साथ ए है तो बी को ए से क्यों प्राप्त नहीं होता है और केवल Foo के बजाय नंबर 3 जोड़ता है? – alun

उत्तर

1

कोड के इस टुकड़े का प्रयास करें:

public class Foo : IEquatable<Foo> 
{ 
    public virtual bool Equals(Foo other) 
    { 
     return true; 
    } 
} 

public class A : Foo,IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public override bool Equals(Foo other) 
    { 
     if (other.GetType() == typeof(A)) 
     { 
      return Equals((A)other);     
     } 
     throw new InvalidOperationException("Object is not of type A"); 
    } 
    public bool Equals(A other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2; 
    } 
} 

public class B : Foo,IEquatable<B> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 
    public int Number3 { get; set; } 

    public override bool Equals(Foo other) 
    { 
     if (other.GetType() == typeof(B)) 
     { 
      return Equals((B)other); 

     } 
     throw new InvalidOperationException("Object is not of type B"); 
    } 
    public bool Equals(B other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2 && this.Number3 == other.Number3; 
    } 
} 

ध्यान दें: आप typechecking करने के लिए जोर कार्यक्षमता का उपयोग कर सकते हैं।

+0

यह ठीक दिखता है, भिखारी पर मैं अमूर्त जैसे फू क्लास स्थापित करने में सोच रहा था। मुझे इस तरह से पसंद है, यह फू क्लास में अजीब वर्चुअल लगता है, फू क्लास को इंटरफेस में बदलना संभव है? –

+0

आगे बढ़ें, पसंद तुम्हारा है, मैंने अभी आपको समाधान प्रदान किया है .... – RockWorld

3

आपके प्रश्न का सीधा उत्तर देने के रूप में, आप हमेशा (कंक्रीट) उप-वर्ग के IEquatable<self> कार्यान्वयन को संदर्भित करके IEquatable<Foo> लागू करने लगते हैं। कुछ इस तरह दिखेगा:

(बुरा कोड, प्रदर्शन के लिए ही)

// You need to specify what you want when this method is called on a 
// vanilla Foo object. I assume here that Foo is abstract. If not, please 
// specify desired behaviour. 
public bool Equals(Foo other) 
{ 
    if (other == null || other.GetType() != GetType()) 
     return false; 

    // You can cache this MethodInfo.. 
    var equalsMethod = typeof(IEquatable<>).MakeGenericType(GetType()) 
              .GetMethod("Equals"); 

    return (bool)equalsMethod.Invoke(this, new object[] { other }); 
} 

लेकिन यह वास्तव में नहीं स्पष्ट कारण है कि आप समानता तुलना की जरूरत हमेशा "के माध्यम से" आधार स्तरीय के जाने के लिए है IEquatable<self> कार्यान्वयन।

ढांचे में पहले से ही आभासी Equals विधि है जिसके परिणामस्वरूप उपयुक्त विधि को समानता-कॉल प्रेषित किया जाएगा। इसके अलावा, EqualityComparar<T>.Default (जो समानता जांच करने के लिए अधिकांश संग्रह-प्रकारों द्वारा उपयोग किया जाता है) पहले से ही में IEquatable<self>.Equals(self) या object.Equals(object) चुनने के लिए स्मारक हैं।

बेस-क्लास में समानता के कार्यान्वयन को बनाने की कोशिश कर रहा है कि अनुरोध के बाद कोई मूल्य कोई भी चीज़ नहीं है, जहां तक ​​मैं देख सकता हूं।

पर आगे स्पष्टीकरण के बिना आपको बेस-क्लास IEquatable<> कार्यान्वयन की आवश्यकता है, मैं केवल प्रत्येक प्रकार पर समानता को लागू करने की अनुशंसा करता हूं। उदाहरण के लिए:

public class A : Foo, IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public bool Equals(A other) 
    { 
     return other != null 
      && Number1 == other.Number1 
      && Number2 == other.Number2; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as A); 
    } 

    public override int GetHashCode() 
    { 
     return Number1^Number2; 
    } 
} 
+0

मुझे लगता है कि आप अपने गैर-जेनेरिक बराबर – alun

+0

@alun में जेनेरिक बराबर के लिए एक कॉल चूक गए हैं: हूप्स, धन्यवाद। फिक्स्ड। – Ani

0

एक विकल्प आधार वर्ग के लिए NUMBER2 और NUMBER1 गुण ले जाने के लिए, और केवल सदस्य उपवर्गों 'समानता के तरीकों में उपवर्ग को जोड़ा गया तुलना है।

class Foo 
{ 
    // move the common properties to the base class 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public override bool Equals(object obj) 
    { 
     Foo objfoo = obj as Foo; 
     return 
      objfoo != null 
      // require objects being compared to be of 
      // the same derived type (optionally) 
      && this.GetType() == obj.GetType() 
      && objfoo.Number1 == this.Number1 
      && objfoo.Number2 == this.Number2; 
    } 
    public override int GetHashCode() 
    { 
     // xor the hash codes of the elements used to evaluate 
     // equality 
     return Number1.GetHashCode()^Number2.GetHashCode(); 
    } 
} 

class A : Foo, IEquatable<A> 
{ 
    // A has no properties Foo does not. Simply implement 
    // IEquatable<A> 

    public bool Equals(A other) 
    { 
     return this.Equals(other); 
    } 

    // can optionally override Equals(object) and GetHashCode() 
    // to call base methods here 
} 

class B : Foo, IEquatable<B> 
{ 
    // Add property Number3 to B 
    public int Number3 { get; set; } 
    public bool Equals(B other) 
    { 
     // base.Equals(other) evaluates Number1 and Number2 
     return base.Equals(other) 
      && this.Number3 == other.Number3; 
    } 
    public override int GetHashCode() 
    { 
     // include Number3 in the hashcode, since it is used 
     // to evaluate equality 
     return base.GetHashCode()^Number3.GetHashCode(); 
    } 
    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as B); 
    } 
} 
0

मुझे लगता है कि व्युत्पन्न कक्षाएं बेस कक्षाओं में नहीं रखी जानी चाहिए। आम तौर पर, "फू" ए और बी

आधार आईईक्वेटेबल कार्यान्वयन वर्चुअल बनाने के लिए अभी भी संभव है, ए और बी को ओवरराइड करने और उनकी विशिष्ट समानता जांच करने की अनुमति देने के लिए अभी भी संभव है, भले ही समानता जांच और जांच की गई दोनों घटनाएं हों केवल "फू" या "ऑब्जेक्ट" के रूप में उपलब्ध हैं।

यह ऑक्वायर (फू ओबीजे) ऑब्जेक्ट के एक विशिष्ट विशिष्ट रूप की तरह होगा (ऑब्जेक्ट ओबीजे)।

संबंधित मुद्दे