कॉपी कंस्ट्रक्टर बनाम क्लोन ()


119

C # में, कक्षा में कार्यक्षमता जोड़ने (गहरी) कॉपी करने का पसंदीदा तरीका क्या है? एक प्रतिलिपि निर्माता को लागू करना चाहिए, या बल्कि से निकाले जाते हैं ICloneableऔर लागू Clone()विधि?

टिप्पणी : मैंने कोष्ठक के भीतर "गहरा" लिखा क्योंकि मुझे लगा कि यह अप्रासंगिक था। जाहिरा तौर पर अन्य लोग असहमत हैं, इसलिए मैंने पूछा कि क्या एक कॉपी कंस्ट्रक्टर / ऑपरेटर / फंक्शन को यह स्पष्ट करने की आवश्यकता है कि कौन सा संस्करण इसे लागू करता है

जवाबों:


91

आपको इससे व्युत्पन्न नहीं होना चाहिए ICloneable

कारण यह है कि जब Microsoft ने .net फ्रेमवर्क डिज़ाइन किया था, तो उन्होंने कभी भी यह निर्दिष्ट नहीं किया कि क्या Clone()विधि ICloneableगहरी या उथली क्लोन होनी चाहिए, इस प्रकार इंटरफ़ेस शब्दार्थ रूप से टूट गया है क्योंकि आपके कॉलर्स को यह पता नहीं चलेगा कि कॉल गहरी होगी या उथली क्लोन वस्तु।

इसके बजाय, आप अपने खुद के परिभाषित करना चाहिए IDeepCloneable(और IShallowCloneable) के साथ इंटरफेस DeepClone()(और ShallowClone()) तरीकों।

आप दो इंटरफेस को परिभाषित कर सकते हैं, एक जेनेरिक पैरामीटर के साथ जोरदार टाइपिंग क्लोनिंग का समर्थन करने के लिए और एक जब आप विभिन्न प्रकार की क्लोन करने योग्य वस्तुओं के संग्रह के साथ काम कर रहे हैं तो कमजोर टाइप किए गए क्लोनिंग की क्षमता रखने के लिए:

public interface IDeepCloneable
{
    object DeepClone();
}
public interface IDeepCloneable<T> : IDeepCloneable
{
    T DeepClone();
}

जिसे आप इस तरह लागू करेंगे:

public class SampleClass : IDeepCloneable<SampleClass>
{
    public SampleClass DeepClone()
    {
        // Deep clone your object
        return ...;
    }
    object IDeepCloneable.DeepClone()   
    {
        return this.DeepClone();
    }
}

आम तौर पर मैं एक कॉपी कंस्ट्रक्टर के विपरीत वर्णित इंटरफेस का उपयोग करना पसंद करता हूं, इससे इरादे बहुत स्पष्ट रहते हैं। एक कॉपी कंस्ट्रक्टर को संभवतः एक गहरा क्लोन माना जाएगा, लेकिन यह निश्चित रूप से एक IDPClonable इंटरफ़ेस का उपयोग करते हुए एक स्पष्ट इरादे के रूप में नहीं है।

यह .net फ्रेमवर्क डिज़ाइन दिशानिर्देशों और ब्रैड अब्राम्स के ब्लॉग पर चर्चा की गई है

(मुझे लगता है कि यदि आप एक आवेदन पत्र लिख रहे हैं (एक रूपरेखा / पुस्तकालय के विपरीत) तो आप यह सुनिश्चित कर सकते हैं कि आपकी टीम के बाहर कोई भी आपके कोड को कॉल नहीं कर रहा है, यह इतना मायने नहीं रखता है और आप एक अर्थ का अर्थ बता सकते हैं "डीपक्लोन" .net ICloneable इंटरफ़ेस के लिए, लेकिन आपको यह सुनिश्चित करना चाहिए कि यह आपकी टीम के भीतर अच्छी तरह से प्रलेखित और अच्छी तरह से समझा गया है। व्यक्तिगत रूप से मैं फ्रेमवर्क दिशानिर्देशों के अनुसार रहना चाहूंगा।)


2
यदि आप एक इंटरफ़ेस के लिए जा रहे हैं, तो DeepClone (T) () और DeepClone (T में से) होने के बारे में (T के रूप में डमी), दोनों में से कौन T लौटाता है? उत्तरार्द्ध वाक्यविन्यास T को तर्क के आधार पर अनुमान लगाने की अनुमति देगा।
सुपरकैट

@ सुपरकैट: क्या आप कह रहे हैं कि एक डमी पैरामीटर है ताकि प्रकार का अनुमान लगाया जा सके? यह एक विकल्प है जो मुझे लगता है। मुझे यकीन नहीं है कि मुझे केवल एक प्रकार का डमी पैरामीटर होने की तरह है जो स्वचालित रूप से अनुमान लगाने के लिए है। शायद मैं तुम्हें गलत समझ रहा हूं। (शायद एक नए उत्तर में कुछ कोड पोस्ट करें ताकि मैं देख सकूं कि आपका क्या मतलब है)।
साइमन पी स्टीवंस

@ सुपरक्रैट: डमी पैरामीटर सही प्रकार के इंजेक्शन की अनुमति देने के लिए मौजूद होगा। ऐसी स्थितियाँ हैं जहाँ कुछ कोड किसी प्रकार के लिए तैयार पहुँच के बिना कुछ क्लोन करना चाहते हैं (उदाहरण के लिए क्योंकि यह एक फ़ील्ड है, संपत्ति है, या फ़ंक्शन किसी अन्य वर्ग से लौटता है) और एक डमी पैरामीटर प्रकार का उल्लेख करने के लिए ठीक से साधन की अनुमति देगा। इसके बारे में सोचते हुए, यह वास्तव में उपयोगी नहीं है क्योंकि एक इंटरफ़ेस का पूरा बिंदु एक गहरी-क्लोन करने योग्य संग्रह की तरह कुछ बनाने के लिए होगा, इस मामले में संग्रह का सामान्य प्रकार होना चाहिए।
सुपरकैट

2
सवाल! आप किस स्थिति में कभी गैर जेनेरिक संस्करण चाहते हैं? मेरे लिए, यह केवल IDeepCloneable<T>अस्तित्व के लिए समझ में आता है, क्योंकि ... आप जानते हैं कि अगर आप अपना खुद का कार्यान्वयन करते हैं, तो टी क्या हैSomeClass : IDeepCloneable<SomeClass> { ... }
काइल बरन

2
@ काइल का कहना है कि आपके पास एक ऐसी विधि थी जो क्लोन करने योग्य वस्तुओं को ले गई थी MyFunc(IDeepClonable data), तब यह सभी क्लोनों पर काम कर सकता था, न कि केवल एक विशिष्ट प्रकार पर। या अगर आपके पास क्लोन का संग्रह था। IEnumerable<IDeepClonable> lotsOfCloneablesतब आप एक ही समय में बहुत सारी वस्तुओं को क्लोन कर सकते हैं। यदि आपको उस तरह की चीज़ की आवश्यकता नहीं है, तो गैर-जेनेरिक को छोड़ दें।
साइमन पी स्टीवंस

33

C # में, कक्षा में कार्यक्षमता जोड़ने के लिए (डीप) कॉपी करने का पसंदीदा तरीका क्या है? क्या किसी को कॉपी कंस्ट्रक्टर को लागू करना चाहिए, या ICloneable से प्राप्त करना चाहिए और क्लोन () विधि को लागू करना चाहिए?

ICloneableजैसा कि दूसरों ने उल्लेख किया है कि यह समस्या है, यह निर्दिष्ट नहीं करता है कि यह एक गहरी या उथली प्रति है, जो इसे व्यावहारिक रूप से अनुपयोगी बना देती है और व्यवहार में, शायद ही कभी इसका उपयोग किया जाता है। यह भी लौटता है object, जो एक दर्द है, क्योंकि इसमें बहुत अधिक कास्टिंग की आवश्यकता होती है। (और यद्यपि आपने विशेष रूप से प्रश्न में कक्षाओं का उल्लेख किया है, ICloneableपर लागू करनाstruct बॉक्सिंग की आवश्यकता है।)

एक प्रतिलिपि अवरोधक भी ICloneable के साथ समस्याओं में से एक से ग्रस्त है। यह स्पष्ट नहीं है कि एक प्रतिलिपि निर्माता एक गहरी या उथली प्रतिलिपि बना रहा है या नहीं।

Account clonedAccount = new Account(currentAccount); // Deep or shallow?

डीपक्लोन () विधि बनाना सबसे अच्छा होगा। इस तरह से मंशा पूरी तरह स्पष्ट है।

यह इस सवाल को उठाता है कि क्या यह एक स्थिर या उदाहरण विधि होना चाहिए।

Account clonedAccount = currentAccount.DeepClone();  // instance method

या

Account clonedAccount = Account.DeepClone(currentAccount); // static method

मैं कभी-कभी स्थैतिक संस्करण को थोड़ा पसंद करता हूं, सिर्फ इसलिए कि क्लोनिंग कुछ ऐसा लगता है जो ऑब्जेक्ट के बजाय किसी वस्तु को किया जा रहा है। या तो मामले में, ऐसे मुद्दों से निपटने के लिए जा रहे हैं जब क्लोनिंग ऑब्जेक्ट्स जो एक वंशानुगत पदानुक्रम का हिस्सा हैं, और उन मुद्दों के साथ कैसे अंत में डिज़ाइन को ड्राइव कर सकते हैं।

class CheckingAccount : Account
{
    CheckAuthorizationScheme checkAuthorizationScheme;

    public override Account DeepClone()
    {
        CheckingAccount clone = new CheckingAccount();
        DeepCloneFields(clone);
        return clone;
    }

    protected override void DeepCloneFields(Account clone)
    {
        base.DeepCloneFields(clone);

        ((CheckingAccount)clone).checkAuthorizationScheme = this.checkAuthorizationScheme.DeepClone();
    }
}

1
हालांकि मुझे नहीं पता कि क्या डीपक्लोन () विकल्प सबसे अच्छा है, मुझे आपका उत्तर बहुत पसंद है, क्योंकि यह भ्रामक स्थिति को रेखांकित करता है जो मेरी राय में बुनियादी प्रोग्रामिंग भाषा सुविधा में मौजूद है। मुझे लगता है कि यह उपयोगकर्ता के लिए चुना गया है कि वह किस विकल्प को पसंद करता है।
दिमित्री सी।

11
मैं यहां बिंदुओं पर बहस नहीं करने जा रहा हूं, लेकिन मेरी राय में, कॉलर को गहरे या उथले के बारे में इतना ध्यान नहीं देना चाहिए जब वे क्लोन () कहते हैं। उन्हें पता होना चाहिए कि उन्हें कोई अमान्य साझा-स्थिति वाला कोई क्लोन मिल रहा है। उदाहरण के लिए, यह पूरी तरह से संभव है कि एक गहरे क्लोन में, मैं हर तत्व को गहरा क्लोन नहीं करना चाहूंगा। क्लोन के कॉल करने वाले को इस बात का ध्यान रखना चाहिए कि वे एक नई प्रति प्राप्त कर रहे हैं जिसमें मूल के लिए कोई अमान्य और असमर्थित संदर्भ नहीं है। 'डीपक्लोन' पद्धति को कॉल करने पर कॉल करने वाले को बहुत अधिक कार्यान्वयन विवरण दिया जाता है।
zumalifeguard

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

8
@KenBeckett - कारण मुझे लगता है कि क्लोनिंग एक वस्तु के लिए किया जाता है क्योंकि एक वस्तु को "एक काम करना चाहिए और इसे अच्छी तरह से करना चाहिए।" आम तौर पर, खुद की प्रतियां बनाना एक वर्ग की मुख्य योग्यता नहीं है, बल्कि यह कार्यक्षमता है जिस पर काम किया जाता है। BankAccount का क्लोन बनाना एक ऐसी चीज है जिसे आप बहुत अच्छी तरह से करना चाहते हैं, लेकिन खुद का क्लोन बनाना बैंक खाते की विशेषता नहीं है। आपका सेल उदाहरण मोटे तौर पर शिक्षाप्रद नहीं है, क्योंकि प्रजनन ठीक वही है जो कोशिकाएँ करने के लिए विकसित हुई हैं। Cell.Clone एक अच्छा उदाहरण विधि होगा, लेकिन यह अन्य चीजों के लिए सच नहीं है।
जेफरी एल व्हाइटलेज

23

मैं मुख्य रूप से एक क्लोन विधि पर एक कॉपी कंस्ट्रक्टर का उपयोग करने की सलाह देता हूं क्योंकि एक क्लोन विधि आपको उन क्षेत्रों को बनाने से रोक readonlyसकती है जो हो सकते थे यदि आपने इसके बजाय एक कंस्ट्रक्टर का उपयोग किया था।

आप बहुरूपी क्लोनिंग की आवश्यकता होती है, तो आप एक जोड़ सकते हैं abstractया virtual Clone()विधि अपने आधार वर्ग के लिए है कि आप प्रति निर्माता के लिए एक कॉल के साथ लागू करते हैं।

यदि आपको एक से अधिक प्रकार की प्रतिलिपि की आवश्यकता होती है (उदाहरण: गहरी / उथली) तो आप इसे कॉपी कंस्ट्रक्टर में एक पैरामीटर के साथ निर्दिष्ट कर सकते हैं, हालांकि मेरे अनुभव में मुझे लगता है कि आमतौर पर गहरी और उथले नकल का मिश्रण होता है जो मुझे चाहिए।

उदाहरण के लिए:

public class BaseType {
   readonly int mBaseField;

   public BaseType(BaseType pSource) =>
      mBaseField = pSource.mBaseField;

   public virtual BaseType Clone() =>
      new BaseType(this);
}

public class SubType : BaseType {
   readonly int mSubField;

   public SubType(SubType pSource)
   : base(pSource) =>
      mSubField = pSource.mSubField;

   public override BaseType Clone() =>
      new SubType(this);
}

8
पॉलीमोर्फिक क्लोनिंग को संबोधित करने के लिए +1; क्लोनिंग का एक महत्वपूर्ण अनुप्रयोग।
samis

18

एक महान तर्क है कि आपको एक संरक्षित प्रतिलिपि निर्माता का उपयोग करके क्लोन () को लागू करना चाहिए

एक संरक्षित (गैर-सार्वजनिक) प्रतिलिपि निर्माता प्रदान करना और क्लोन विधि से इसे लागू करना बेहतर है। यह हमें एक वर्ग के एक उदाहरण के लिए एक वस्तु बनाने के कार्य को सौंपने की क्षमता देता है, इस प्रकार से सुरक्षा प्रदान करता है और साथ ही, संरक्षित प्रतिलिपि निर्माता का उपयोग करके वस्तुओं को सुरक्षित रूप से बनाता है।

तो यह "बनाम" प्रश्न नहीं है। आपको इसे करने के लिए कॉपी कंस्ट्रक्टर (ओं) और क्लोन इंटरफ़ेस दोनों की आवश्यकता हो सकती है।

(हालांकि अनुशंसित सार्वजनिक इंटरफ़ेस कंस्ट्रक्टर-आधारित के बजाय क्लोन () इंटरफ़ेस है।)

अन्य उत्तरों में स्पष्ट गहरे या उथले तर्क में न फंसे। वास्तविक दुनिया में यह लगभग हमेशा कुछ के बीच में होता है - और किसी भी तरह से, कॉलर की चिंता नहीं होनी चाहिए।

क्लोन () अनुबंध केवल "जब मैं पहले एक को बदलूंगा तो परिवर्तन नहीं होगा"। आपको कितना ग्राफ कॉपी करना है, या आप अनन्त पुनरावृत्ति से कैसे बचें, ऐसा होने से फोन करने वाले को चिंता नहीं होनी चाहिए।


"कॉल करने वाले की चिंता नहीं होनी चाहिए"। मैं और अधिक सहमत नहीं हो सकता था, लेकिन यहां मैं यह जानने की कोशिश कर रहा हूं कि सूची <T> aList = नई सूची <T> (aFullListOfT) एक गहरी प्रतिलिपि (जो मैं चाहता हूं) या एक उथले प्रतिलिपि (जो टूट जाएगा) मेरा कोड) और मुझे काम पूरा करने के लिए एक और तरीका लागू करना है या नहीं!
थंडरग्रास

3
क्लोन करने के लिए एक सूची <T> बहुत सामान्य है (हा हा) भी समझ में आता है। आपके मामले में, यह निश्चित रूप से सूची की केवल एक प्रति है और सूची द्वारा इंगित वस्तुओं को नहीं। नई सूची में हेरफेर करने से पहली सूची प्रभावित नहीं होगी, लेकिन वस्तुएं समान हैं और जब तक वे अपरिवर्तनीय नहीं होती हैं, तब तक वे पहले सेट में बदल जाएंगे यदि आप दूसरे सेट में परिवर्तन करते हैं। यदि आपकी लाइब्रेरी में एक सूची थी। Clone () ऑपरेशन, तो आपको उम्मीद करनी चाहिए कि परिणाम एक पूर्ण क्लोन के रूप में होगा "जब मैं पहले वाले के लिए कुछ करूंगा तो वह नहीं बदलेगा।" जो निहित वस्तुओं पर भी लागू होता है।
डैनो

1
एक सूची <टी> यह ठीक से क्लोनिंग के बारे में अधिक जानने के लिए नहीं है कि यह आपके मुकाबले सामग्री है। यदि अंतर्निहित वस्तु अपरिवर्तनीय है, तो आप जाने के लिए अच्छे हैं। अन्यथा, यदि अंतर्निहित ऑब्जेक्ट में क्लोन () विधि है, तो आपको इसका उपयोग करना होगा। सूची <T> aList = नई सूची <T> (aFullListOfT.Select (t = t.Clone ())
DanO

1
संकर दृष्टिकोण के लिए +1। दोनों दृष्टिकोणों में एक फायदा और नुकसान है, लेकिन यह अधिक समग्र लाभ है।
काइल बरन

12

लागू करने योग्य ICloneable की इस तथ्य के कारण अनुशंसित नहीं है कि यह निर्दिष्ट नहीं है कि क्या यह एक गहरी या उथली प्रतिलिपि है, इसलिए मैं निर्माणकर्ता के लिए जाऊंगा, या बस कुछ खुद को लागू करूंगा। शायद इसे DeepCopy () कहते हैं ताकि यह वास्तव में स्पष्ट हो सके!


5
@ जी, कंस्ट्रक्टर रिले का इरादा कैसे करता है? IOW, यदि कोई ऑब्जेक्ट खुद को कंस्ट्रक्टर में लेता है, तो क्या कॉपी गहरी है या उथली है? अन्यथा, मैं DeepCopy () या (अन्यथा) सुझाव से पूरी तरह सहमत हूं।
मार्क

7
मेरा तर्क है कि एक निर्माता लगभग ICloneable इंटरफ़ेस के रूप में अस्पष्ट है - आपको यह जानने के लिए एपीआई डॉक्स / कोड पढ़ना होगा कि यह एक गहरा क्लोन करता है या नहीं। मैं सिर्फ IDeepCloneable<T>एक DeepClone()विधि के साथ एक इंटरफ़ेस को परिभाषित करता हूं ।
कैंट बूगार्ट

2
@ जॉन - रिएक्टरिंग कभी खत्म नहीं हुआ!
ग्रांट क्रॉफ्टन

@Marc, @ कांट - हाँ उचित बिंदु, निर्माता शायद एक अच्छा विचार नहीं है।
ग्रांट क्रॉफ्टन

3
क्या किसी ने एक प्रयोग देखा है जहाँ iCloneable का उपयोग अज्ञात प्रकार की वस्तु पर किया गया था? इंटरफेस का पूरा बिंदु यह है कि उनका उपयोग अज्ञात प्रकार की वस्तुओं पर किया जा सकता है; अन्यथा कोई भी बस क्लोन बना सकता है एक मानक विधि है जो प्रश्न में प्रकार देता है।
सुपरकैट

12

आप कॉपी निर्माता और अमूर्त कक्षाओं के साथ समस्याओं में भाग लेंगे। आप निम्नलिखित करना चाहते हैं कल्पना कीजिए:

abstract class A
{
    public A()
    {
    }

    public A(A ToCopy)
    {
        X = ToCopy.X;
    }
    public int X;
}

class B : A
{
    public B()
    {
    }

    public B(B ToCopy) : base(ToCopy)
    {
        Y = ToCopy.Y;
    }
    public int Y;
}

class C : A
{
    public C()
    {
    }

    public C(C ToCopy)
        : base(ToCopy)
    {
        Z = ToCopy.Z;
    }
    public int Z;
}

class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>();

        B b = new B();
        b.X = 1;
        b.Y = 2;
        list.Add(b);

        C c = new C();
        c.X = 3;
        c.Z = 4;
        list.Add(c);

        List<A> cloneList = new List<A>();

        //Won't work
        //foreach (A a in list)
        //    cloneList.Add(new A(a)); //Not this time batman!

        //Works, but is nasty for anything less contrived than this example.
        foreach (A a in list)
        {
            if(a is B)
                cloneList.Add(new B((B)a));
            if (a is C)
                cloneList.Add(new C((C)a));
        }
    }
}

उपरोक्त करने के ठीक बाद, आप चाहते हैं कि आप या तो एक इंटरफ़ेस का उपयोग करें, या एक DeepCopy () / ICloneable.Clone () कार्यान्वयन के लिए व्यवस्थित हो जाएं।


2
इंटरफ़ेस-आधारित दृष्टिकोण के लिए अच्छा तर्क।
दानो १

4

ICloneable के साथ समस्या मंशा और निरंतरता दोनों है। यह कभी स्पष्ट नहीं है कि यह एक गहरी या उथली प्रति है। इस वजह से, यह शायद केवल एक ही तरीके से या किसी अन्य तरीके से उपयोग नहीं किया जाता है।

मुझे उस मामले पर कोई स्पष्ट होने के लिए एक सार्वजनिक प्रतिलिपि निर्माता नहीं मिला।

उस ने कहा, मैं आपके लिए काम करने वाली एक विधि प्रणाली शुरू करूंगा और इरादे से भरोसा रखूंगा (कुछ हद तक स्व दस्तावेज)


3

यदि आप जिस ऑब्जेक्ट को कॉपी करने की कोशिश कर रहे हैं, वह Serializable है तो आप इसे क्रमबद्ध करके और इसे deserializing करके क्लोन कर सकते हैं। फिर आपको प्रत्येक वर्ग के लिए एक कॉपी कंस्ट्रक्टर लिखने की आवश्यकता नहीं है।

मेरे पास अभी कोड नहीं है, लेकिन यह कुछ इस तरह है

public object DeepCopy(object source)
{
   // Copy with Binary Serialization if the object supports it
   // If not try copying with XML Serialization
   // If not try copying with Data contract Serailizer, etc
}

6
गहरी क्लोनिंग को लागू करने के साधन के रूप में क्रमांकन का उपयोग इस सवाल के लिए अप्रासंगिक है कि क्या गहरे क्लोन को एक ctor या विधि के रूप में सामने आना चाहिए।
कैंट बूगार्ट

1
मुझे लगता है कि यह एक और वैध विकल्प है। मुझे नहीं लगा कि वह गहरी नकल के उन दो तरीकों तक सीमित था।
शॉन बोवे

5
@ केंट बूआगार्ट - ओपी को लाइन "सी # में शुरू होता है, यह देखते हुए कि एक वर्ग के लिए (गहरी) कॉपी कार्यक्षमता जोड़ने का पसंदीदा तरीका क्या है", मुझे लगता है कि शॉन के लिए विभिन्न विकल्पों की पेशकश करना काफी उचित है। विशेष रूप से एक विरासत परिदृश्य में जहां आपके पास बड़ी संख्या में कक्षाएं हैं जिनके लिए आप क्लोन कार्यक्षमता को लागू करना चाहते हैं, यह चाल उपयोगी हो सकती है; अपने स्वयं के क्लोन को सीधे लागू करने के रूप में हल्का नहीं है, लेकिन फिर भी उपयोगी है। अगर लोगों ने कभी भी "मेरे सवालों के बारे में नहीं सोचा है ..." की पेशकश की है, तो मैंने पिछले कुछ वर्षों में जितना सीखा है, उतना मैंने नहीं सीखा है।
रोब लेविन

2

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

मेरे लिए:

// myobj is some transparent proxy object
var state = new ObjectState(myobj.State);

// do something

myobject = GetInstance();
var newState = new ObjectState(myobject.State);

if (!newState.Equals(state))
    throw new Exception();

के बजाय:

// myobj is some transparent proxy object
var state = myobj.State.Clone();

// do something

myobject = GetInstance();
var newState = myobject.State.Clone();

if (!newState.Equals(state))
    throw new Exception();

आशय के स्पष्ट कथन के रूप में देखा गया।


0

मुझे लगता है कि क्लोन करने योग्य वस्तुओं के लिए एक मानक पैटर्न होना चाहिए, हालांकि मुझे यकीन नहीं है कि पैटर्न क्या होना चाहिए। क्लोनिंग के संबंध में, ऐसा लगता है कि तीन प्रकार की कक्षाएं हैं:

  1. जो गहरी क्लोनिंग के लिए स्पष्ट रूप से समर्थन करते हैं
  2. उन है कि जहां सदस्यवार क्लोनिंग गहरी क्लोनिंग के रूप में काम करेंगे, लेकिन जिनके पास न तो स्पष्ट समर्थन की आवश्यकता है और न ही।
  3. जो उपयोगी रूप से गहरे क्लोन नहीं किए जा सकते हैं, और जहां सदस्यवार क्लोनिंग खराब परिणाम देगा।

जहाँ तक मैं बता सकता हूँ, एक ही वर्ग के एक नए ऑब्जेक्ट को प्राप्त करने का एकमात्र तरीका (कम से कम .net 2.0) में मौजूदा ऑब्जेक्ट के रूप में एक सदस्य का उपयोग करना है। ऐसा लगता है कि एक अच्छा पैटर्न "नया" / "छाया" फ़ंक्शन क्लोन है जो हमेशा वर्तमान प्रकार को लौटाता है, जिसकी परिभाषा सदैव मेंबरवाइज़ क्लोन को कॉल करने के लिए होती है और फिर एक संरक्षित वर्चुअल सबरूटीन क्लीनअपक्लोन (ओरिऑबजेक्ट) को कॉल करना होता है। CleanupCode रूटीन को आधार के क्लोनिंग की जरूरतों को संभालने के लिए base.Cleanupcode को कॉल करना चाहिए और फिर अपना स्वयं का क्लीनअप जोड़ना चाहिए। यदि क्लोनिंग रूटीन को मूल ऑब्जेक्ट का उपयोग करना है, तो उसे टाइपकास्ट करना होगा, लेकिन अन्यथा केवल टाइपकास्टिंग मेम्बरवाइज़लोन कॉल पर होगी।

दुर्भाग्य से, वर्ग का निम्नतम स्तर जो टाइप (1) के बजाय टाइप (2) से ऊपर था, को यह मानने के लिए कोडित करना होगा कि इसके निचले प्रकारों को क्लोनिंग के लिए किसी स्पष्ट समर्थन की आवश्यकता नहीं होगी। मैं वास्तव में उसके आसपास कोई रास्ता नहीं देखता।

फिर भी, मुझे लगता है कि एक परिभाषित पैटर्न होने से बेहतर कुछ नहीं होगा।

संयोग से, अगर किसी को पता है कि किसी का आधार प्रकार iCloneable का समर्थन करता है, लेकिन उसके द्वारा उपयोग किए जाने वाले फ़ंक्शन का नाम नहीं जानता है, तो क्या किसी के आधार प्रकार के iCloneable.Clone फ़ंक्शन को संदर्भित करने का कोई तरीका है?


0

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

मैं एक सामान्य एक्सटेंशन विधि का उपयोग करके 3 पार्टी वर्गों के गुणों को "गहराई से" कैसे कर सकता हूं?

यह वर्णन करता है कि एक विस्तार विधि को कैसे लागू किया जाए CreateCopy()जो सभी गुणों सहित ऑब्जेक्ट की "गहरी" प्रतिलिपि बनाता है (मैन्युअल रूप से संपत्ति द्वारा संपत्ति की नकल करने के बिना)।

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