2017-07-17 11 views
8

मैं सी # डीप कॉपी और शालो कॉपी सीख रहा हूं। Demo_obj1 में परिवर्तन के बाद, ऑब्जेक्ट वैल्यू बदल दिया गया है लेकिन सूची अपडेट नहीं की गई है, लेकिन demo_obj2 ऑब्जेक्ट वैल्यू बदल दी गई है और सूची मूल्य भी अपडेट किया गया है। किसी को पता है कि यहाँ क्या हो रहा है? धन्यवादक्लोन में अजीब परिणाम()

दृश्य स्टूडियो 2017

नेट ढांचे 4,6

public class Demo : ICloneable 
{ 
    public int Value { get; set; } 

    public string UID { get; set; } 

    public Demo(int nValue) 
    { 
     Value = nValue; 
    } 

    public object Clone() 
    { 
     return this.MemberwiseClone(); 
    } 
} 

public class Program 
{ 
    public static void Print(List<Demo> objList) 
    { 
     Console.WriteLine(); 
     foreach (Demo objDemo in objList) 
     { 
      Console.WriteLine("{0} = {1}", objDemo.UID, objDemo.Value); 
     } 
    } 
    public static void Main() 
    { 
     List<Demo> objList = new List<Demo>(); 

     Demo obj1 = new Demo(100); 
     obj1.UID = "Demo_obj1"; 

     Demo obj2 = (Demo)obj1.Clone(); 
     obj2.UID = "Demo_obj2"; 

     objList.Add(obj1); 
     objList.Add(obj2); 

     Print(objList); 

     obj1 = obj2; 
     obj1.Value = 200; 

     Console.WriteLine(); 
     Console.WriteLine(obj1.UID + " = " + obj1.Value); 
     Console.WriteLine(obj2.UID + " = " + obj2.Value); 

     Print(objList); 
     Console.ReadKey(); 
    } 
} 

आउटपुट:

Demo_obj1 = 100 
Demo_obj2 = 100 

Demo_obj2 = 200 
Demo_obj2 = 200 

Demo_obj1 = 100 
Demo_obj2 = 200 
+0

@VladimirArustamian वह पहले से ही –

+0

पर अपने कोड में सदस्यwiseक्लोन का उपयोग करता है एक और वर्णनात्मक शीर्षक उचित होगा। – user1803551

उत्तर

6

क्लोनिंग के साथ इसका कोई लेना-देना नहीं है, यह संदर्भ मुद्दा है।

आपने दो ऑब्जेक्ट obj1 और obj2 बनाए हैं और उन्हें एक सूची में रखा है।
अब, आप संग्रह के माध्यम से पुन: प्रयास करते हैं, इसे आउटपुट करते हैं और अपेक्षित परिणाम प्राप्त करते हैं।

संदर्भ अब निम्नलिखित हैं:

obj1, list[0] -> Demo_obj1 (100) 
obj2, list[1] -> Demo_obj2 (100) 

Output list[0] => Demo_obj1 (100) 
Output list[1] => Demo_obj2 (100)  

बाद में, obj1 = obj2 करके, आप obj1 करने के लिए obj2 के संदर्भ सौंपा है। आप अपना मूल्य बदल नहीं रहे हैं या अपनी ऑब्जेक्ट की प्रतिलिपि नहीं बना रहे हैं, आप बस संदर्भ की प्रतिलिपि बनाते हैं और इसे किसी अन्य ऑब्जेक्ट पर इंगित करते हैं।
तो, वास्तव में, दोनों अब एक ही वस्तु को इंगित करते हैं।
सूची में विभिन्न वस्तुओं के समान दो संदर्भ शामिल हैं।

list[0]    -> Demo_obj1 (100) 
obj1, obj2, list[1] -> Demo_obj2 (100) 

तो फिर तुम obj2.Value = 200 बनाने वास्तव में से 200 अपने मूल्य बदल रहा है:

list[0]    -> Demo_obj1 (100) 
obj1, obj2, list[1] -> Demo_obj2 (200) 

आप उत्पादन obj1 और obj2 UIDs और मूल्यों के लिए अब का प्रयास करते हैं, तो आप करेंगे एक ही वस्तु की वास्तव में उत्पादन मूल्य (Demo_obj2)।

Output obj1 => Demo_obj2 (200) 
Output obj2 => Demo_obj2 (200) 

हालांकि, अगर आप संग्रह के माध्यम से पुनरावृति करने की कोशिश, आप Demo_obj1 और Demo_obj2 फिर से मिल जाएगा, संदर्भ तालिका के अनुसार।

Output list[0] => Demo_obj1 (100) 
Ouptut list[1] => Demo_obj2 (200) 
3

आप चर obj1 निर्धारित किया है उदाहरण obj2 में आयोजित किया जाना है। obj1 का मूल मान अभी भी सूची में मौजूद है। उस लाइन पर जहां आप obj1 = obj2; करते हैं, यह obj2 को पकड़ने के लिए चर obj1 सेट कर रहा है। यह उस उदाहरण के मानों को प्रतिस्थापित नहीं करता है जिसे पहले obj1 में संग्रहीत किया गया था। यही कारण है कि आप अपने द्वारा वर्णित आउटपुट देख रहे हैं।

5

तो मुझे लगता है कि इस प्रश्न से आपको कुछ बिंदुओं को समझने की आवश्यकता है।

सबसे पहले आपके वास्तविक प्रश्न के संबंध में, clone() विधि वास्तव में आपको 2 ऑब्जेक्ट देती है। वे दोनों 100 मान से शुरू होते हैं और एक सूची में जोड़े जाते हैं। ध्यान दें कि यह सूची obj1 और obj2 के भीतर मौजूद वस्तुओं को इंगित करती है और आपके द्वारा पहले से बनाए गए संदर्भों का उपयोग नहीं करती है।

तो फिर तुम ऐसा करते हैं:

obj1 = obj2; 
obj1.Value = 200; 

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

अंत में जब आप अपने दूसरे लॉग चलाने के लिए, सूची आप मूल्य 100 और दूसरा obj2 जो आप 200 का मान होना करने के लिए अद्यतन के साथ मूल obj1 देखने के भीतर संकेत का उपयोग कर।


अब यहाँ दिलचस्प बात यह है, यह है, एक गहरी क्लोन का एक बहुत अच्छा उदाहरण वास्तव में नहीं है, क्योंकि आप आदिम मूल्यों है कि बस वैसे भी कॉपी हो जाएगा का उपयोग कर रहे है।

class Bar 
{ 
    public int Value; 
    public Bar(int value) 
    { 
     this.value = value; 
    } 
}  

class Foo : ICloneable 
{ 
    public String Id; 
    public Bar MyBar; 

    public Foo(int value) { 
     this.MyBar = new Bar(value); 
    } 

    public object Clone() 
    { 
     return this.MemberwiseClone(); 
    } 
} 

अब अगर आप अब एक Foo की एक उथले क्लोन एक बार का निर्माण और ऐसा करने के लिए थे, यह अभी भी एक ही Bar का उपयोग करेंगे: बेहतर परिणाम आप शायद किसी वस्तु में कुछ मान रैप करने के लिए चाहते हैं प्राप्त करने के लिए। तो:

Foo f = new Foo(100); 
Foo f2 = (Foo)f.Clone(); 

f2.MyBar.Value = 200; 

Console.WriteLine(f.MyBar.Value); // 200 
Console.WriteLine(f2.MyBar.Value); // 200 

यह जहां इतनी है कि Foo उदाहरणों में से प्रत्येक के लिए एक अनूठा Bar के लिए एक अलग संदर्भ का उपयोग दीप क्लोनिंग में प्राप्त करने की आवश्यकता होगी।

+0

उत्तर के लिए धन्यवाद – QweRty

+0

एक क्लोनबल ऑब्जेक्ट के अंदर संदर्भ प्रकार के बारे में अच्छा बिंदु – Fredou

3

MemberwiseClone भूल जाएं, यह यहां एक लाल हेरिंग है।

आपका यहां मुद्दा यह है:

obj1 = obj2; 
obj1.Value = 200; 
  1. चर मूल्यों के लिए प्लेसहोल्डर हैं।
  2. संदर्भ टाइप किए गए चर में संग्रहीत मान "पता" है जहां ऑब्जेक्ट इसकी स्मृति में "जीवन" संदर्भित करता है।
  3. वैरिएबल, डिफ़ॉल्ट रूप से, सी # में मान द्वारा प्रतिलिपि बनाई जाती हैं।

तो, यह मतलब है कि obj1 = obj2; obj1.Value = 200; निम्नलिखित है:।।

  1. (obj2 में संग्रहीत मूल्य पता नहीं है जहां उदाहरण { "Demo_obj2"; 100 } जीवन
  2. कॉपी कि डी चर obj1 में मूल्य प्राप्त अब obj1 मान वह पता है जहां एक ही उदाहरण { "Demo_obj2"; 100 } रहता है; obj1 और obj2एक ही ऑब्जेक्ट पर इंगित करता है।
  3. obj1 (या obj2) 200 पर संदर्भित ऑब्जेक्ट के Value को बदलें: परिणाम { "Demo_obj2"; 200 } है।
  4. उदाहरण { "Demo_obj1"; 100 } पहले obj1 द्वारा संदर्भित सूची में अपने दो चर obj1 या obj2 में से किसी से अब और संदर्भित है नहीं, लेकिन उदाहरण अभी भी संग्रहीत किया जाता है (आप इसे छुआ है!) और objList[0] माध्यम से पहुंच योग्य।

क्या आप अब समझते हैं कि आप जो व्यवहार देख रहे हैं उसे क्यों प्राप्त कर रहे हैं?

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