2010-07-08 40 views
6

में List<int> के पीछे तर्क को समझने में असमर्थ हूं क्योंकि यह कुछ बुनियादी नियमों को तोड़ता है।सूची <int> सी #

List<int> मान प्रकार का होना चाहिए और संदर्भ प्रकार नहीं होना चाहिए।

  1. List<int>ref कीवर्ड द्वारा प्रदान किया जाने वाला है, तो अपने मूल्य फ़ंक्शन कॉल के बीच एक समान होने के लिए गया है। तो इसका मतलब है कि यह int के समान मूल्य प्रकार व्यवहार प्रदर्शित कर रहा है।
  2. लेकिन List<int> को एक नए ऑपरेटर द्वारा प्रारंभ किया जाना है। List<int> भी शून्य हो सकता है। यह एक संदर्भ प्रकार व्यवहार का तात्पर्य है।

इसमें एक शून्य प्रकार अलग है क्योंकि इसमें नए ऑपरेटर द्वारा प्रारंभ नहीं किया जाना चाहिए।

क्या मैं यहां कुछ गलत देख रहा हूं?

EDITED-

मैं मूल प्रश्न अपने आप में कोड पोस्ट किया जाना चाहिए था। लेकिन यह यहां इस प्रकार है -

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ListTest d = new ListTest(); 
      d.Test(); 
     } 
    } 

    class ListTest 
    { 
     public void ModifyIt(List<int> l) 
     { 
      l = returnList(); 
     } 

     public void Test() 
     { 
      List<int> listIsARefType = new List<int>(); 
      ModifyIt(listIsARefType); 
      Console.WriteLine(listIsARefType.Count); // should have been 1 but is 0 
      Console.ReadKey(true); 
     } 

     public List<int> returnList() 
     { 
      List<int> t = new List<int>(); 
      t.Add(1); 
      return t; 
     } 
    } 
} 
+3

आपके बिंदु 1 के साथ आपका क्या मतलब है? क्या आप एक उदाहरण दे सकते हैं कि आपको क्यों लगता है कि आपको 'रेफरी' की आवश्यकता है? –

+0

@ 0xA3 => एक विधि 1 बनाएं जो इसकी पैरामीटर के रूप में सूची लेता है। फिर मुख्य विधि पास विधि 1 में एक सूची । विधि 1 में सूची में कुछ पूर्णांक जोड़ें। मुख्य विधि में देखें कि क्या आप उन पूर्णांक को वापस प्राप्त करते हैं। – Prashant

+0

mattmc3 पहले से ही एक उदाहरण पोस्ट किया गया है जो दर्शाता है कि आपको 'ref' की आवश्यकता नहीं है। –

उत्तर

27

सूची मूल्य प्रकार की होनी चाहिए और प्रकार को संदर्भित नहीं माना जाता है।

गलत!int एक मूल्य प्रकार है। List<int> एक संदर्भ प्रकार है।

+0

यदि ऐसा होता है तो फ़ंक्शन के बीच सूची को रेफ़री करके क्यों पास किया जाता है? – Prashant

+4

@Prash आप ऐसा करेंगे यदि आप संदर्भ को बदलना चाहते हैं (यानी: इसे शून्य या एक अलग सूची में सेट करें)। लेकिन मैं सामान्य रूप से आवश्यक बनाने के लिए कोड नहीं बनाऊंगा। –

+3

@ प्रशांत: आपको इसकी आवश्यकता नहीं है। जो भी आपको बताता है कि आप हमेशा करते हैं, एक मूर्ख है। 'रेफरी' कीवर्ड क्या करता है, आपको पैरामीटर को एक अन्य 'सूची ' पर सेट करने की अनुमति देता है। जो लगभग उतना ही आम नहीं है जितना आपको लगता है कि यह है। – cHao

2

List<int> वास्तव में एक संदर्भ प्रकार है। लेकिन सूची में निहित आइटम मूल्य प्रकार हैं।

शून्य प्रकारों को हालांकि structs (struct Nullable<T> where T : struct) के रूप में लागू किया गया है और इसलिए मूल्य प्रकार हैं।

Nullable<Int32> i = new Nullable<Int32>(3); 

का एक बेहतर समझ पाने के लिए: कारण यह है कि आप बस new कीवर्ड बिना

int? i = 3; 

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

Jon Skeet: Parameter passing in C#

1

एक List एक सामान्य संदर्भ प्रकार, आप एक मूल्य प्रकार int के साथ प्रयोग कर रहे हैं है। लेकिन यह अभी भी एक संदर्भ प्रकार है।

2

इसे List<int> के रूप में न सोचें, जिस तरह से यह लिखा गया था कि यह List<t> लिखा गया था।

सूची जेनेरिक क्लास है। यह एक संरचना नहीं है। यह एक सामान्य वर्ग है जो मूल्य प्रकारों और संदर्भ प्रकारों के साथ काम कर सकता है।

0

List<int> एक संदर्भ प्रकार है। और इसे एक संदर्भ के रूप में पारित करने की आवश्यकता नहीं है।

वस्तुओं में के प्रकार सूची में, एक मान प्रकार तरह-की है, सिवाय इसके कि मूल्य प्रकार वस्तुओं को समाप्त कर सकते हैं बॉक्स्ड (एक प्रकार का संदर्भ प्रकार की वस्तुओं में परिवर्तित) वैसे भी, इस so..scratch एक बार जब आप इसे समझते हैं तो अनुच्छेद।

+0

ध्यान दें कि 'सूची '* * मुक्केबाजी की आवश्यकता नहीं है। केवल तभी यदि आप 'सूची ' में मूल्य मान डालते हैं तो मुक्केबाजी शामिल होगी। –

+0

@ 0xA3: मुझे यकीन नहीं था कि नेट ने कितनी अच्छी तरह से किया था। मैं जावा के बारे में परेशान जानता हूं, लेकिन इसके इंटीग्रर्स प्राइमेटिव ऑब्जेक्ट्स की तरह दिखने के लिए आधा दिल का प्रयास करते हैं, जबकि नेट की "प्राइमेटिव्स" वास्तविक वस्तुएं हैं। – cHao

7

मुझे लगता है कि आपके पहले बुलेट में आपको एक दोषपूर्ण धारणा है। सामान्य सूची वस्तु निश्चित रूप से एक संदर्भ प्रकार है (ढेर पर, ढेर नहीं)। सुनिश्चित नहीं है कि आपको लगता है कि आपको ref के माध्यम से गुजरना है। की तरह यह होना चाहिए "2" यह प्रिंट:

namespace ConsoleApplication1 { 
    class Program { 
     static void Main(string[] args) { 
     List<int> listIsARefType = new List<int>(); 
     ModifyIt(listIsARefType); 
     ModifyIt(listIsARefType); 
     Console.WriteLine(listIsARefType.Count); // 2! 
     Console.ReadKey(true); 
     } 

     static void ModifyIt(List<int> l) { 
     l.Add(0); 
     } 
    } 
} 
+0

मुझे लगता है कि यह ध्यान रखना महत्वपूर्ण है कि किसी भी सूची इस तथ्य के कारण एक संदर्भ प्रकार है कि यह एक बेसटाइप से बनाया गया था जो एक संदर्भ प्रकार है। यह ध्यान दिया जाना चाहिए कि सूची में मौजूद एक आइटम संभावित रूप से संदर्भ प्रकार नहीं है लेकिन यह एक संदर्भ प्रकार बन सकता है। – msarchet

6

आप मूल्य द्वारा संदर्भ, मूल्य द्वारा पास, और पास संदर्भ द्वारा पास के बीच अंतर को समझना होगा।

कोड नमूना आप पोस्ट, आप मूल्य द्वारा List<int> वस्तु को संदर्भ गुजर रहे हैं। इसका मतलब है कि आप संदर्भ द्वारा इंगित ऑब्जेक्ट को म्यूटेट कर सकते हैं, और कॉलिंग कोड इन परिवर्तनों को देखेगा। हालांकि, संदर्भ स्वयं मान द्वारा पारित किया जाता है, इसलिए यदि आप संदर्भ को किसी भिन्न ऑब्जेक्ट पर संदर्भित करते हैं, तो कॉलिंग कोड में परिवर्तन दिखाई नहीं देंगे।

जब आप ref कीवर्ड का उपयोग करते हैं, तो आप संदर्भ के संदर्भ में संदर्भ पारित कर रहे हैं। इसका मतलब है कि न केवल उस ऑब्जेक्ट को बदल सकता है जिस पर संदर्भ इंगित कर रहा है, लेकिन आप संदर्भ को भी बदल सकते हैं।

class Program 
{ 
    static void Main() 
    { 
     int foo = 0; 
     DoSomething1(foo); 
     Console.WriteLine(foo); // Outputs 0. 

     DoSomething1(ref foo); 
     Console.WriteLine(foo); // Outputs 1. 

     var bar = new List<int>(); 
     DoSomething2(bar); 
     Console.WriteLine(bar.Count); // Outputs 1. 

     DoSomething2(ref bar); 
     Console.WriteLine(bar.Count); // Outputs 0. 
    } 

    // Pass by value. 
    static void DoSomething1(int number) 
    { 
     // Can't modify the number! 
     number++; 
    } 

    // Pass by value. 
    static void DoSomething1(ref int number) 
    { 
     // Can modify the number! 
     number++; 
    } 

    // Pass reference by value. 
    static void DoSomething2(List<int> list) 
    { 
     // Can't change the reference, but can mutate the object. 
     list.Add(25); 
    } 

    // Pass reference by reference. 
    static void DoSomething2(ref List<int> list) 
    { 
     // Can change the reference (and mutate the object). 
     list = new List<int>(); 
    } 
} 
0

अन्य उत्तर में निपटा गलत मान्यताओं के अलावा, आप कहते हैं:

इस उदाहरण पर विचार

List<int> एक नए ऑपरेटर द्वारा प्रारंभ हो गया है ... यह संदर्भ प्रकार व्यवहार का तात्पर्य है।

नहीं, सी # new ऑपरेटर में केवल एक प्रकार के निर्माता को कॉल करने के लिए वाक्यविन्यास है। इसका उपयोग संदर्भ और उपयोगकर्ता परिभाषित मूल्य प्रकार दोनों के लिए किया जाता है (struct एस)।

0

ModifyIt() विधि में, जब आप 'l = returnList()' लिख रहे हैं; 'एल' अब आपके टेस्ट() विधि में सूची ISARefType की तुलना में स्मृति में एक अलग स्थान की ओर इशारा कर रहा है। मूल रूप से 'एल' '=' कुछ लिखकर, आपने 'एल' और 'listIsarefType' के बीच का लिंक तोड़ दिया है। लिंक को रखने के लिए (यह सुनिश्चित कर रहा है कि दोनों ऑब्जेक्ट्स, 'एल' और 'listIsarefType' स्मृति में एक ही स्थान पर इंगित कर रहे हैं), आपको या तो केवल 'l' ऑब्जेक्ट पर काम करने की आवश्यकता है (उदाहरण के लिए ऑब्जेक्ट पर फ़ंक्शन कॉल करके), या ModifyIt() विधि के पैरामीटर में रेफरी कीवर्ड का उपयोग करें।

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