2010-10-13 2 views
7

कोई इसStruct v/s कक्षा सी में # - कृपया विस्तार से बताएं व्यवहार

class testCompile 
    { 
     /* 
     * Sample Code For Purpose of Illustration 
     */ 
     struct person 
     { 
      public int age; 
      public string name; 

     } 

     static void Main(string[] args) 
     { 
      List<person> Listperson = new List<person>(); 
      person myperson = new person(); 

      for (int i = 1; i <= 2; i++) 
      { 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 
      int x = 0; 
      while (x < Listperson.Count) 
      { 
       //Output values 
       Console.WriteLine("{0} - {1}", Listperson[x].name, Listperson[x].age); 
       x++; 
      } 
     } 
    } 

/* 
    Output: 
    Person - 1 - 23 
    Person - 2 - 24 
*/ 

के व्यवहार क्यों मैं एक struct के रूप में एक वर्ग के लिए एक ही उत्पादन हो रही है नहीं कर रहा हूँ कृपया समझा सकते हैं?

class testCompile 
    { 
     /* 
     * Sample Code For Purpose of Illustration 
     */ 
     class person 
     { 
      public int age; 
      public string name; 

     } 

     static void Main(string[] args) 
     { 
      List<person> Listperson = new List<person>(); 
      person myperson = new person(); 

      for (int i = 1; i <= 2; i++) 
      { 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 
      int x = 0; 
      while (x < Listperson.Count) 
      { 
       //Output values 
       Console.WriteLine("{0} - {1}", Listperson[x].name, Listperson[x].age); 
       x++; 
      } 
     } 
    } 
/* 
    Output: 
    Person - 2 - 24 
    Person - 2 - 24 
*/ 
+0

ऐसा इसलिए है क्योंकि ढेर पर ढांचे के उदाहरण आवंटित किए जाते हैं और कक्षाओं के उदाहरण ढेर पर आवंटित किए जाते हैं। ओह। – jason

+1

@ जेसन: नहीं, इस बारे में बहुत भ्रम है कि मूल्य प्रकार बनाम संदर्भ प्रकार संग्रहीत किए जाते हैं। एरिक के उत्कृष्ट ब्लॉग पोस्ट को पढ़ने के लिए सर्वश्रेष्ठ: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx –

+0

@ 0xA3: आपका अंदरूनी मजाक उबाऊ हास्य डिटेक्टर विफल – jason

उत्तर

17

क्लासेस संदर्भ प्रकार के होते हैं, structs मूल्य प्रकार हैं।

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

एक संदर्भ प्रकार एक पैरामीटर के रूप में एक विधि के लिए पारित किया जाता है, संदर्भ के माध्यम से पारित हो जाएगा। इसका मतलब है कि आप दो उसी स्मृति स्थान के संदर्भ की प्रतियां (उसी Person ऑब्जेक्ट में) जोड़ते हैं - जब इस ऑब्जेक्ट में परिवर्तन करते हैं, तो आप इसे दोनों संदर्भों में प्रतिबिंबित करते हैं क्योंकि वे दोनों एक ही ऑब्जेक्ट को संदर्भित करते हैं।

+0

@ 0xA3 - नाइट के लिए धन्यवाद ... उत्तर अपडेट किया गया, उम्मीद है कि अब इसे चुना गया है;) – Oded

4

क्योंकि आपका myperson variable केवल एक व्यक्ति संरचना/वर्ग से संबंधित है।

जो आप अपनी लूप में सूची में जोड़ते हैं, वह आपके मायनेर्स वैरिएबल की एक प्रति है - जो संरचना के लिए, संरचना की एक पूरी प्रति होगी, लेकिन कक्षा के लिए संदर्भ की एक प्रति होगी एक उदाहरण के लिए जिसे आप बनाते हैं (और उत्परिवर्तित)।

1

दूसरे उदाहरण में आप केवल आइटम पर बना रहे हैं और कई बार सूची में संदर्भ जोड़ रहे हैं।

5

यह मूल्य प्रकार (संरचना) और संदर्भ प्रकार (कक्षा) के बीच का अंतर है।

  • आप Listperson व्यक्ति की सामग्री सूची में डाल दिया है करने के लिए struct जोड़ रहे हैं, तो आप अपनी सूची में दो अलग-अलग व्यक्ति struct है।

    for (int i = 1; i <= 2; i++) 
    { 
        //Assignment 
        myperson.age = 22+i; 
        myperson.name = "Person - " + i.ToString(); 
        Listperson.Add(myperson); 
        /* First time: 
        Listperson contains a person struct with value { age = 23, name = 1} 
        Second iteration: 
        Listperson contains a person struct with value { age = 23, name = 1} 
        Listperson contains another person struct with value { age = 24, name = 2} 
        */ 
    } 
    
  • जब आप कक्षा संदर्भ सूची में डाल दिया जाता है जोड़ रहे हैं, तो आप दो संदर्भों है कि एक ही व्यक्ति ऑब्जेक्ट का संदर्भ दिया है।

    for (int i = 1; i <= 2; i++) 
    { 
        //Assignment 
        myperson.age = 22+i; 
        myperson.name = "Person - " + i.ToString(); 
        Listperson.Add(myperson); 
        /* First time: 
        Listperson contains 1 reference to myperson object with value { age = 23, name = 1} 
        Second iteration: 
        Listperson contains 2 reference to myperson object with value { age = 24, name = 2} 
        */ 
    } 
    
2

दूसरे उदाहरण में, आप एक संदर्भ प्रकार addding रहे हैं। वास्तव में, आप एक ही आइटम जोड़ रहे हैं, दो बार, अपने

= new person() 

के बाद से पाश में नहीं है। तो यह हमेशा आपके द्वारा शुरू की गई उसी वस्तु को इंगित करता है:

person myperson = new person(); 

आपकी सूची में जोड़े जाने के बाद भी, परिवर्तन इसे प्रभावित करते हैं।

पहले उदाहरण में, आप प्रत्येक बार एक संरचना जोड़ रहे हैं, जो एक मान प्रकार है, इसलिए सूची में कॉपी किया जाएगा। आपके द्वारा किए गए परिवर्तन अब सूची में ऑब्जेक्ट को संदर्भित नहीं करते हैं, इसलिए उनके पास अलग-अलग मान हैं।

1

जब आप संग्रह में संरचना जोड़ते हैं, तो यह इसकी एक प्रति बनाता है। यह मान प्रकार है। आप संग्रह में दो अलग-अलग वस्तुओं के साथ समाप्त होंगे, प्रत्येक अलग-अलग मानों के साथ। यह शायद अपेक्षित व्यवहार है।

जब आप कक्षा में जोड़ें, संदर्भ प्रकार, संग्रह में, एक नई वस्तु नहीं बनाई गई है। आप वास्तव में एक ही ऑब्जेक्ट में दो अलग-अलग संदर्भ जोड़ रहे हैं। आप एक ही मूल्य के साथ दो वस्तुओं (स्पष्ट रूप से) के साथ समाप्त हो जाएगा। यह वास्तव में एक ही वस्तु है, जो संग्रह में दो बार दिखाई दे रहा है।

2

संरचनाएं मूल्य प्रकार हैं और कक्षा संदर्भ प्रकार हैं। तो आपके पहले उदाहरण में जब आप मेरी व्यक्ति को सूची में जोड़ते हैं तो आप मेरी प्रतिलिपि की प्रतिलिपि जोड़ते हैं और मायनेर्स वैरिएबल अभी भी एक अलग प्रति को संदर्भित करता है। आपके दूसरे उदाहरण में मेरा व्यक्ति एक संदर्भ प्रकार है ताकि आप एक ही ऑब्जेक्ट में दो पॉइंटर्स जोड़ सकें।

2

आपको structs (Value Types) और कक्षाओं (Reference Type) के बीच महत्वपूर्ण अंतर समझना चाहिए। आप आसानी से Google या SO पर यह जानकारी पा सकते हैं।

जब आप सूची में संरचना उदाहरण जोड़ते हैं तो आप इस उदाहरण के लिए एक और अलग प्रतिलिपि बनाते हैं, और जब आप एक तत्व बदलते हैं तो आपने कोई दूसरा नहीं बदला है।

लेकिन कक्षाओं के मामले में आप एक उदाहरण बनाते हैं और दो संदर्भों (सूची [0] और 1) के साथ इस "साझा" उदाहरण का उपयोग करते हैं और आप इसे एक उदाहरण को दो अलग-अलग संदर्भों के माध्यम से बदल सकते हैं, यही कारण है कि जब आप बदलते हैं सूची [0] आइटम ऐसा लगता है कि आप सूची 1 आइटम भी बदलते हैं।

कोड निम्नलिखित पर विचार करें:

var s1 = new SampleStruct { X = 1, Y = 1 }; 
var s2 = s1; 
//Creating separate copy 
//Lets check this 
Console.WriteLine(object.ReferenceEquals(s1, s2)); //Prints False 

var c1 = new SampleClass { X = 1, Y = 2 }; 
var c2 = c1; 
//We do not create any copy 
// two references c1 and c2 "pointed" to one shared object 
Console.WriteLine(object.ReferenceEquals(c1, c2)); //Prints True 

इसी प्रकार के व्यवहार हमारे पास जब हम (या तत्व जोड़ सूची) कार्य करने के लिए पैरामीटर गुजरती हैं।

4

आप एक ही परिणाम तो पाश के लिए के अंदर व्यक्ति घोषणा लाने चाहते हैं: -

  // person myperson = new person(); 
      //Move the upper line inside the for loop 
      for (int i = 1; i <= 2; i++) 
      { 
       person myperson = new person(); 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 

struct में आप हैं, इसलिए अलग-अलग मान जमा हो जाती है एक मान प्रकार जोड़ने जबकि कक्षा में आप वस्तु के संदर्भ में जोड़ रहे हैं इसलिए एक ही मूल्य मिलना।

+0

मुझे इसके बारे में पता है। धन्यवाद। – abhi

0

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

तो कोड की तरह:

 
{ 
    Car A,B,C; /* Car is a class */ 
    A = new Car; 
    B = new Car; 
    C = A; 
    A.color = carColors.Yellow; 
    B.color = C.color; 
} 

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

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