2012-03-27 5 views
6

उदाहरणआईएस (टाइप चेक) को कम करने के लिए पॉलिमॉर्फिज्म + ओवरलोडिंग का उपयोग करके इस विधि को कैसे सुधारें?

BaseClass MyBase() 
{ 
    public int Add(BaseClass next) 
    { 
     if (this is InheritedA && next is InheritedA) 
      return 1; 
     else if (this is InheritedA && next is InheritedB) 
      return 2; 
     else if (this is InheritedB && next is InheritedA) 
      return 3; 
     else if (this is InheritedB && next is InheritedB) 
      return 4;  
    } 
} 

जहां InheritedA के लिए, और InheritedB अपनी विरासत में मिला वर्ग हैं। वास्तव में, वहाँ और अधिक पारंपरिक रूप से प्राप्त कक्षाएं हैं, और आदेश और उसके संकार्य के प्रकार के आधार Add रिटर्न अलग परिणाम।

मैं पॉलिमॉर्फिज्म और ओवरलोडिंग का उपयोग करके इसे फिर से लिखने की सोच रहा हूं, हालांकि, यह जटिल हो जाता है, मुझे किसी भी प्रकार के प्रकार को हल करने के लिए एक सहायक विधि पेश करना है।

उदा।

InheritedA myA() 
{ 
    public override int Add(BaseClass next) 
    { 
     return next.AddTo(this); 
    } 
} 

अब मैं BaseClass में AddTo रखा, और साथ ही विरासत में मिला वर्ग में ओवरराइड कर दिया है।

InheritedA myA() 
{ 
    public override int AddTo(InheritedA next) { return 1; } 
    public override int AddTo(InheritedB next) { return 3; } 
} 

BaseClass myBase() 
{ 
    public abstract int Add(BaseClass next); 
    public abstract int AddTo(InheritedA next); 
    public abstract int AddTo(InheritedB next); 
} 

क्या ऐसा करने का कोई बेहतर तरीका है?

+0

एक बार इनहेरिट सी कक्षा होने पर क्या होता है? आईई ए + सी = ए + बी करता है? – Sign

+0

क्या प्रत्येक ऑपरेंड (लालसा और रावल) के लिए केवल दो मान हैं? – CAbbott

+0

@CAbbott मैं इस प्रतिबंध का पालन करने के लिए अपनी कक्षा को संशोधित कर सकता हूं, इसलिए हाँ केवल दो मान – colinfang

उत्तर

1

जैसा कि टिप्पणियों में सुझाव दिया गया था, यदि आप प्रत्येक व्युत्पन्न के लिए निरंतर मूल्य आवंटित करने में सक्षम हैं, तो आप Value नामक वर्चुअल प्रॉपर्टी के साथ यहां एक बहुत अधिक क्लीनर कार्यान्वयन कर सकते हैं या इसी तरह अतिरिक्त के लिए इस्तेमाल किया।

यह मानते हुए कि नहीं है एक विकल्प है, तो आप मान प्रत्येक संयोजन के लिए बताए रहे हैं वर्णन करने के लिए विचार करने के लिए पूर्व की गणना आधार वर्ग स्तर पर परिणामों चाह सकते हैं। यह टूट सकता है और वर्गों के सेट के रूप में त्रुटि प्रवण और थकाऊ हो सकता है, इसलिए मैं केवल इस पर विचार करने का सुझाव दूंगा यदि आप एक बहुत छोटे सेट को बनाए रखने की उम्मीद करते हैं।

मेरी मौलिक उदाहरण में, मैं सेट और हार्ड-कोडेड संयोजन धारण करने के लिए एक शब्दकोश का इस्तेमाल किया। आपकी टिप्पणी से, ऐसा प्रतीत होता है कि अंकगणितीय के मूलभूत नियमों में से कोई भी लागू नहीं होता है, इसलिए मैंने उन्हें यहां बाधाओं के रूप में छोड़ दिया है। यदि परिणाम मूल्य का कोई वास्तविक अर्थ नहीं है और आप इसे अभी बढ़ा रहे हैं, तो आप व्युत्पन्न कक्षाओं को खींचने और प्रत्येक संयोजन पर विचार करने के लिए प्रतिबिंब का उपयोग करके परिणाम सेट बनाने पर विचार कर सकते हैं।

public class BaseClass 
{ 
    private static readonly Dictionary<int, int> addResults = new Dictionary<int, int>(); 

    static BaseClass() 
    { 
    addResults.Add(CreateKey(typeof(ChildA), typeof(ChildA)), 1); 
    addResults.Add(CreateKey(typeof(ChildA), typeof(ChildB)), 2); 
    addResults.Add(CreateKey(typeof(ChildB), typeof(ChildA)), 3); 
    addResults.Add(CreateKey(typeof(ChildB), typeof(ChildB)), 4); 
    } 

    public static int CreateKey(Type a, Type b) 
    { 
    return (String.Concat(a.Name, b.Name).GetHashCode()); 
    } 

    public int Add(BaseClass next) 
    { 
    var result = default(int); 

    if (!addResults.TryGetValue(CreateKey(this.GetType(), next.GetType()), out result)) 
    { 
     throw new ArgumentOutOfRangeException("Unknown operand combination"); 
    } 

    return result; 
    } 
} 

public class ChildA : BaseClass {} 
public class ChildB : BaseClass {} 
+0

मुझे डर है कि यह मेरे संस्करण 1 से धीमा होगा? – colinfang

+0

प्रदर्शन पर अनुमान लगाने में हमेशा मुश्किल होती है, लेकिन मैं अपेक्षा करता हूं कि प्रदर्शन प्रतिनिधि डेटा सेट पर तुलनात्मक हो। पूर्व-गणना कार्यान्वयन के लिए गणना किए गए सेट को बनाने के लिए थोड़ा अधिक ओवरहेड की आवश्यकता होती है। "कॉल" करने के लिए प्रत्येक कॉल को प्रति कॉल एक बार समामेलन और हैश मान गणना करने के लिए स्मृति आवंटित करने की आवश्यकता होगी। प्रारंभिक कार्यान्वयन खंड में "है" ऑपरेटर का उपयोग करके सशर्त की प्रत्येक शाखा के लिए GetType के बराबर कर रहा है। जब तक कि आप रीयल-टाइम सिस्टम में नहीं हैं, मुझे नहीं लगता कि प्रदर्शन दोनों के बीच एक सार्थक मानदंड है। –

8

पैटर्न आप कार्यान्वित कर रहे हैं डबल आभासी प्रेषण कहा जाता है।

एक एकल आभासी प्रेषण चुनता है जो विधि रन-टाइम प्रकार रिसीवर के और तर्कों की संकलन समय प्रकार के आधार पर कॉल करने के लिए। यह एक पारंपरिक आभासी प्रेषण है:

abstract class Animal {} 
class Tiger : Animal {} 
class Giraffe : Animal {} 
class B 
{ 
    public virtual void M(Tiger x) {} 
    public virtual void M(Animal x) {} 
} 
class D : B 
{ 
    public override void M(Tiger x) {} 
    public override void M(Animal x) {} 
} 
... 
B b = whatever; 
Animal a = new Tiger(); 
b.M(a); 

किस विधि को बुलाया जाता है? B.M(Tiger) और D.M(Tiger) नहीं चुने गए हैं; हम तर्क है, जो पशु है की संकलन समय प्रकार के आधार पर उन्हें अस्वीकार करते हैं। लेकिन हम पर है कि क्या whatevernew B() या new D() है आधारित रनटाइम पर B.M(Animal) या D.M(Animal) कॉल करने के लिए कि क्या चुनें।

डबल आभासी प्रेषण चुनता है जो विधि दो बातें के क्रम प्रकार के आधार पर कॉल करने के लिए।यदि सी # समर्थित डबल आभासी प्रेषण, जो यह नहीं करता है, तो रनटाइम प्रेषण B.M(Tiger) या D.M(Tiger) पर जाएगा, भले ही तर्क का संकलन-समय प्रकार पशु है।

सी # 4 हालांकि गतिशील प्रेषण का समर्थन करता है। आप

dynamic b = whatever; 
dynamic a = new Tiger(); 
b.M(a); 

कहना तो हैं एम के विश्लेषण पूरी तरह से क्रम पर किया जाएगा b और a के क्रम प्रकार का उपयोग कर। यह काफी धीमा है, लेकिन यह काम करता है।

वैकल्पिक रूप से, के रूप में ज्यादा विश्लेषण संभव के रूप में संकलन समय पर किया है, तो आप डबल आभासी प्रेषण करते हैं और प्राप्त करना चाहते हैं तो ऐसा करने के लिए मानक तरीका है आगंतुक पैटर्न, आप पर देख सकते हैं जो लागू करने के लिए आसानी से इंटरनेट।

+0

यह सब जानने के लिए वास्तव में अच्छा है। आपने कहा "रिसीवर का रन-टाइम प्रकार और तर्कों का संकलन समय प्रकार" .. लेकिन आप क्यों कहते हैं कि रनटाइम प्रकार "ए" पशु नहीं है और इसके बजाय बाघ है? मुझे पता है कि मैं निश्चित रूप से बाघ को टाइप कर सकता हूं लेकिन टाइपकास्टिंग से पहले "ए" का प्रकार अभी भी पशु है। नहीं ? – Dhananjay

+1

@ डंकुलकर्णी, कुछ रनटाइम प्रकार रनटाइम पर वास्तविक प्रकार है। और यहां वास्तविक प्रकार 'टाइगर 'है, क्योंकि वास्तव में यह' ए 'में संग्रहीत होता है (या इसके बजाय,' टाइगर' का संदर्भ है)। – svick

+1

@ डंकुलकर्णी: प्रकार * चर * प्रकार है। यह अभिव्यक्ति का "संकलन समय प्रकार" है। अभिव्यक्ति का "रनटाइम प्रकार" उस चीज का प्रकार है जो वास्तव में चर में संग्रहीत होता है। –

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