2012-10-19 7 views
6

चलो कहते हैं कि मैं निम्नलिखित वर्ग पदानुक्रम है (आधार इंटरफ़ेस शामिल है) करते हैं:सी # कक्षा पदानुक्रम में गहरी प्रतिलिपि/क्लोन विधियां - क्या मुझे हर जगह एक ठोस कार्यान्वयन की आवश्यकता है?

IAction -> (abstract) BaseAction -> (concrete) ImmediateAction -> (concrete) MovementAction 

अब मान लें कि IAction एक विधि को उजागर करता है चलो (ठीक है, वास्तव में एक अलग इंटरफेस है कि IAction औजार लेकिन चीजों को सरल यहां रहने देती हैं, करता है!) :

// Returns a new IAction instance deep copied from the current instance. 
IAction DeepClone(); 

अभी तक अच्छा है? हम अपने गहरे प्रतिलिपि विधि है, और ImmediateAction कुछ गुण है कि यह तो यह न केवल DeepClone() के एक कार्यान्वयन प्रदान करेगा कॉपी किया चाहता है, लेकिन एक प्रति के साथ-साथ निर्माता:

//Base Action implementation 
protected BaseAction(BaseAction old) 
{ 
    this.something = old.something; 
} 

//Immediate Action Implementation 
protected ImmediateAction(ImmediateAction old) 
    : base(old) 
{ 
    this.anything = old.anything; 
} 

public IAction DeepClone() 
{ 
    return new ImmediateAction(this); 
} 

अब मान लें कि MovementAction नहीं है चलो इसके अंदर कुछ भी जो DeepClone() में प्रासंगिक है, इसलिए यह विधि या प्रतिलिपि कन्स्ट्रक्टर को लागू नहीं करता है। - जो एक नई ImmediateAction को दर्शाता है MovementActionDeepClone() को लागू नहीं करता, इसलिए ImmediateAction.DeepClone() बजाय कहा जाता है,

IAction x = new MovementAction(); 
IAction y = x.DeepClone(); 

//pleaseBeTrue is false 
bool pleaseBeTrue = y is MovementAction; 

अब, मैं समझ यहाँ क्या हो रहा है:

समस्या यह है कि मैं आ रही है यह है। इसलिए, ऊपर दिए गए उदाहरण में y का प्रकार MovementAction के बजाय ImmediateAction है।

तो, इस लंबी प्रस्तुति के बाद, मेरा प्रश्न यह है: इस प्रकार की स्थिति के लिए सबसे अच्छा अभ्यास क्या है? क्या मैं अटक गया हूँ? क्या मैं DeepClone() विधि लागू करने के लिए पदानुक्रम के साथ प्रत्येक वर्ग के लिए कोई फर्क नहीं पड़ता? क्या पैटर्न मैं यहां गलत उपयोग कर रहा हूं, और बेहतर तरीका है?

एक अंतिम नोट: यदि संभव हो तो मैं प्रतिबिंब से बचना चाहूंगा।

+0

आप प्रतिबिंब से बचना क्यों चाहते हैं? –

+0

इसका उपयोग किसी गेम में और संभावित रूप से गेमप्ले के दौरान किया जा रहा है और न केवल लोड हो रहा है, इसलिए यदि संभव हो तो मैं प्रतिबिंब के ऊपरी हिस्से से बचना चाहता हूं। एक छोटी सी पृष्ठभूमि: आम तौर पर जेएसओएन/एक्सएमएल परिभाषाओं के माध्यम से चीजों को एलोलोड किया जाता है, लेकिन IAction फैक्ट्री (और अन्य कारखानों) प्रकार के द्वारा IActions कैश करता है, और फिर से लोड करने के लिए एक्सएमएल पर जाने से बचने के लिए संग्रहीत संदर्भ क्लोन करता है।(पूलिंग एक और विकल्प था, लेकिन कई संभावित प्रकार के कार्यों के साथ, सभी अलग-अलग गुणों के साथ और इस तरह मैं पूलिंग समाधान को संभावित रूप से सैकड़ों अलग-अलग पूल के बिना व्यवहार्य नहीं देख सकता) – Terminal8

+0

मुझे इरादे का मुद्दा लगता है। यदि आप चीजों को 'IAction' के रूप में संभालने की योजना बना रहे हैं और 'डीपक्लोन' नामक किसी भी वस्तु के मूल प्रकार को संरक्षित करना महत्वपूर्ण है, तो आप उन सभी ठोस वर्गों पर 'दीपक्लोन' लिखेंगे जो 'IAction' को लागू करते हैं। 'और यह सुनिश्चित करेगा कि आपको सही प्रकार की ऑब्जेक्ट मिल जाए। सौभाग्य से, उनको लिखना मुश्किल है। – itsmatt

उत्तर

2

का उपयोग कर, लेकिन साझा कार्यान्वयन एक विस्तार विधि का उपयोग कर सकते हैं और वृद्धिशील क्लोनिंग

public static class DeepCopyExt 
{ 
    public static T DeepCopy<T>(this T item) 
     where T : ThingBase, new() 
    { 
     var newThing = new T(); 
     item.CopyInto(newThing); 
     return newThing; 
    } 
} 

public abstract class ThingBase 
{ 
    public int A { get; set; } 

    public virtual void CopyInto(ThingBase target) 
    { 
     target.A = A; 
    } 
} 

public class ThingA : ThingBase 
{ 
} 

public class ThingB : ThingA 
{ 
    public int B { get; set; } 

    public override void CopyInto(ThingBase target) 
    { 
     var thingB = target as ThingB; 

     if(thingB == null) 
     { 
      throw new ArgumentException("target is not a ThingB"); 
     } 

     thingB.B = B; 
     base.CopyInto(thingB); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var b = new ThingB 
     { 
      A = 1, 
      B = 3 
     }; 

     //c is ThingB 
     var c = b.DeepCopy(); 

     var b1 = new ThingA 
     { 
      A = 1, 
     }; 

     //c1 is ThingA 
     var c1 = b1.DeepCopy(); 

     Debugger.Break(); 
    } 
} 
+0

मुझे कहना है, मुझे यह समाधान पसंद है! एक कम है प्रति वर्ग ('डीपक्लोन' और प्रतिलिपि बनाने के बजाय 'प्रतिलिपि' को लागू करने की बात) और यह ऑब्जेक्ट त्वरण को एक लाख स्थान 'डीपक्लोन() के प्रसार के बजाय एक ही स्थान पर रखता है, इसलिए पूलिंग हो सकती है एक आसान जोड़ भी! धन्यवाद! – Terminal8

0

आमतौर पर आपको ठोस वर्गों में अपनी क्लोन विधि को लागू करने की आवश्यकता होगी। वास्तव में इस कोड को आप पोस्ट अगर ImmediateAction संकलन नहीं होगा सार है जैसे आप शीर्ष पर कहा:

return new ImmediateAction(this); 
+0

आह, यह मेरी गलती थी। तत्काल अमूर्त नहीं है। – Terminal8

2

तो हाँ, आप दो विकल्प हैं:

  • या तो DeepClone (लागू) हर बार और विवरण (सूची बिल्कुल नहीं से साझा की गई गुण)
  • या प्रयोग 'जल्दी & गंदा' प्रतिबिंब
संबंधित मुद्दे