C# में डीप कॉपी: हर डेवलपर की परेशानी क्यों?
\n\nक्या आपने कभी C# में किसी ऑब्जेक्ट को कॉपी किया, और फिर हैरानी से पाया कि "कॉपी" में बदलाव करने से मूल ऑब्जेक्ट भी बदल गया? यह शैलो कॉपी (shallow copy) की क्लासिक समस्या है। जब किसी ऑब्जेक्ट में रेफरेंस फील्ड्स (दूसरे क्लास, लिस्ट, ऐरे) होते हैं, तो MemberwiseClone() सिर्फ रेफरेंस कॉपी करता है। नतीजा, मूल और कॉपी दोनों एक ही नेस्टेड ऑब्जेक्ट को पॉइंट करते हैं।
इस आर्टिकल में हम C# में deep cloning को समझेंगे — यानी सभी नेस्टेड ऑब्जेक्ट्स के साथ पूरी तरह से स्वतंत्र कॉपी बनाना। हम 5 लोकप्रिय तरीकों की तुलना करेंगे, रियल कोड लिखेंगे, बेंचमार्क करेंगे और जानेंगे कि आपके प्रोजेक्ट के लिए कौन सा तरीका सबसे अच्छा है।
\n\nDeep Clone क्या है और Shallow Clone से कैसे अलग है?
\n\nमान लीजिए आपके पास एक Person क्लास है जिसमें Address है:
public class Address\n{\n public string City { get; set; }\n public string Street { get; set; }\n}\n\npublic class Person\n{\n public string Name { get; set; }\n public int Age { get; set; }\n public Address HomeAddress { get; set; }\n}\n\nShallow clone (सामान्य MemberwiseClone()) में आपको एक नया Person मिलेगा, लेकिन उसका HomeAddress मूल ऑब्जेक्ट के उसी Address ऑब्जेक्ट को पॉइंट करेगा। कॉपी में सड़क का नाम बदला — मूल में भी बदल गया। यह एक आपदा है।
Deep clone इस समस्या को हल करता है: यह सभी नेस्टेड ऑब्जेक्ट्स को रिकर्सिवली कॉपी करके पूरी तरह से स्वतंत्र डेटा स्ट्रक्चर बनाता है।
\n\nतरीका 1: ICloneable और कॉपी कंस्ट्रक्टर के ज़रिए मैन्युअल इम्प्लीमेंटेशन
\n\nसबसे आसान, लेकिन सबसे ज़्यादा मेहनत वाला तरीका — ICloneable इंटरफ़ेस को इम्प्लीमेंट करना या अपना DeepClone() मेथड लिखना।
इम्प्लीमेंटेशन का उदाहरण:
\n\npublic class Address : ICloneable\n{\n public string City { get; set; }\n public string Street { get; set; }\n\n public object Clone()\n {\n return new Address { City = this.City, Street = this.Street };\n }\n}\n\npublic class Person : ICloneable\n{\n public string Name { get; set; }\n public int Age { get; set; }\n public Address HomeAddress { get; set; }\n\n public object Clone()\n {\n return new Person\n {\n Name = this.Name,\n Age = this.Age,\n HomeAddress = (Address)this.HomeAddress?.Clone()\n };\n }\n}\n\nफायदे:
\n- \n
- कॉपी करने की प्रक्रिया पर पूरा नियंत्रण \n
- सबसे अच्छा परफॉरमेंस \n
- कोड समझने में आसान (कोई "जादू" नहीं) \n
नुकसान:
\n- \n
- बहुत ज़्यादा boilerplate कोड \n
- नया फील्ड जोड़ने पर Clone() मेथड को अपडेट करना भूलना आसान \n
- थर्ड-पार्टी क्लासेस (जैसे लाइब्रेरी से) के लिए काम नहीं करता \n
कब उपयोग करें: केवल 2-3 फील्ड वाले सरल DTO के लिए, जहाँ परफॉरमेंस महत्वपूर्ण हो (जैसे गेम इंजन में)।
\n\nतरीका 2: रिफ्लेक्शन (Reflection) — सबका साथी
\n\nरिफ्लेक्शन की मदद से आप एक ऐसा deep cloning मेथड लिख सकते हैं जो किसी भी ऑब्जेक्ट के साथ काम करेगा।
\n\nकोड का उदाहरण:
\n\npublic static T DeepCloneByReflection<T>(T source)\n{\n if (source == null) return default;\n\n var type = source.GetType();\n \n // वैल्यू टाइप और स्ट्रिंग के लिए सीधा मान लौटाएँ\n if (type.IsValueType || type == typeof(string))\n return source;\n\n // ऐरे के लिए\n if (type.IsArray)\n {\n var arr = source as Array;\n var clonedArr = Array.CreateInstance(type.GetElementType(), arr.Length);\n for (int i = 0; i < arr.Length; i++)\n clonedArr.SetValue(DeepCloneByReflection(arr.GetValue(i)), i);\n