2009-07-22 12 views
8

मैंने अभी सी # में एक स्वैप दिनचर्या बनाई है:सी #+ में एक ही पॉइंटर्स सी # में रेफ और आउट हैं?

static void Swap(ref int x, ref int y) 
{ 
    int temp = x; 
    x = y; 
    y = temp; 
} 

यह वही काम करता है जो यह सी ++ कोड करता है:

void swap(int *d1, int *d2) 
{ 
    int temp=*d1; 
    *d1=*d2; 
    *d2=temp; 
} 

तो ref और out कीवर्ड हैं जो बिना उपयोग किए सी # के पॉइंटर्स हैं unsafe कोड?

उत्तर

10

वे अधिक सीमित हैं। आप पॉइंटर पर ++ कह सकते हैं, लेकिन ref या out पर नहीं।


संपादित टिप्पणी में कुछ भ्रम की स्थिति है, तो बिल्कुल स्पष्ट होना करने के लिए: यहां मुद्दा यह संकेत की क्षमताओं के साथ तुलना करने के लिए है। आप ptr++ पर ref/out पर एक ही ऑपरेशन नहीं कर सकते हैं, यानी इसे स्मृति में आसन्न स्थान को संबोधित करते हैं। यह सच है (लेकिन यहां अप्रासंगिक) कि आप (*ptr)++ के समतुल्य प्रदर्शन कर सकते हैं, लेकिन यह मान की क्षमताओं के साथ इसकी तुलना करना होगा, पॉइंटर्स नहीं।


यह एक सुरक्षित शर्त है कि वे आंतरिक रूप से सिर्फ संकेत दिए गए हैं, क्योंकि ढेर ले जाया नहीं प्राप्त करता है और सी # ध्यान से आयोजित किया जाता है ताकि ref और out हमेशा ढेर के एक सक्रिय क्षेत्र के सन्दर्भ में है।


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

इसके विपरीत जब ref/out जीसी ढेर में वस्तुओं को संदर्भित करता है यह कोई आश्चर्य की बात है कि उन वस्तुओं जब तक आवश्यक के रूप में जीवित रखा जा करने में सक्षम हैं: जीसी ढेर समय के किसी भी लम्बाई के लिए बनाए रखने की वस्तुओं के प्रयोजन के लिए ठीक डिज़ाइन किया गया है उनके संदर्भकर्ताओं द्वारा आवश्यक, और परिस्थितियों का समर्थन करने के लिए पिनिंग (नीचे उदाहरण देखें) प्रदान करता है जहां ऑब्जेक्ट को जीसी कॉम्पैक्टिंग द्वारा स्थानांतरित नहीं किया जाना चाहिए।


क्या तुमने कभी असुरक्षित कोड में इंटरॉप के साथ खेलते हैं, तो आप पाएंगे कि ref बहुत बारीकी से संकेत से संबंधित है।उदाहरण के लिए, एक COM इंटरफेस इस तरह घोषित किया जाता है, तो:

HRESULT Write(BYTE *pBuffer, UINT size); 

इंटरॉप विधानसभा इस में बदल जाएगा:

void Write(ref byte pBuffer, uint size); 

और आप इस कॉल करने के लिए (मेरा मानना ​​है कि COM इंटरॉप सामान कर सकते हैं सरणी) pinning का ख्याल रखता है: पहली बाइट आप इसे के सभी के लिए पहुँच हो जाता है करने के लिए

byte[] b = new byte[1000]; 
obj.Write(ref b[0], b.Length); 

दूसरे शब्दों में, ref; यह स्पष्ट रूप से पहले बाइट के लिए एक सूचक है।

+0

आप 'रेफरी' तर्क पर '++' ठीक कर सकते हैं, लेकिन इसका मतलब यह नहीं है। –

+0

इसके अलावा, "' ref' और 'out' हमेशा स्टैक के सक्रिय क्षेत्र को संदर्भित करता है" बस पूरी तरह से गलत है। आपका स्वयं का उदाहरण जीसी ढेर पर किसी ऑब्जेक्ट में 'रेफरी' बनाता है। –

6

सी # में संदर्भ पैरामीटर एक पॉइंटर्स का उपयोग करने के लिए उपयोग किया जा सकता है, हां। लेकिन सब नहीं।

पॉइंटर्स के लिए एक और आम उपयोग एक सरणी पर पुनरावृत्ति के साधन के रूप में है। आउट/रेफ पैरामीटर ऐसा नहीं कर सकते हैं, इसलिए नहीं, वे "पॉइंटर्स के समान नहीं" हैं।

1

संक्षिप्त उत्तर हाँ है (समान कार्यक्षमता, लेकिन बिल्कुल एक ही तंत्र नहीं)। एक साइड नोट के रूप में, यदि आप अपने कोड का विश्लेषण करने के लिए FxCop का उपयोग करते हैं, तो out और ref का उपयोग करके "CA1045: DoNotPassTypesByReference" की "Microsoft.Design" त्रुटि होगी।

1

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

2

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

इनमें से सभी निस्संदेह कवर के तहत पॉइंटर्स हैं।

+0

संवैधानिक रूप से वे वास्तव में पॉइंटर्स को अधिक बारीकी से मिलते हैं, क्योंकि आपको 'रेफरी' प्रीपेड करना होगा, जैसे कि आपको सी/सी ++ में पॉइंटर प्राप्त करने के लिए '&' प्रीपेड करना होगा। –

+0

(मेरा मतलब कॉलिंग साइट पर है।) –

+0

तो वे वास्तव में बीच में कहीं हैं (क्योंकि इसे पढ़ने/लिखने पर आपको इसे अव्यवस्थित करने की आवश्यकता नहीं है)। –

3

ref और out केवल फ़ंक्शन तर्कों के साथ उपयोग किया जाता है ताकि यह संकेत दिया जा सके कि तर्क मूल्य के बजाय संदर्भ द्वारा पारित किया जाना है। इस अर्थ में, हां, वे कुछ हद तक सी ++ में पॉइंटर्स की तरह हैं (वास्तव में संदर्भों की तरह अधिक)। this article में इसके बारे में और पढ़ें।

1

तुलनात्मक रूप से तुलनाकर्ताओं की नजर में हैं ... मैं नहीं कहता हूं। 'रेफरी' कॉलिंग सम्मेलन बदलता है लेकिन पैरामीटर के टाइप नहीं करता है। आपके सी ++ उदाहरण में, डी 1 और डी 2 प्रकार int * हैं। सी # में वे अभी भी Int32 हैं, वे केवल मूल्य के बजाय संदर्भ द्वारा पारित होने के लिए होता है।

वैसे, आपका सी ++ कोड वास्तव में पारंपरिक अर्थों में अपने इनपुट को स्वैप नहीं करता है। इतना है कि यह सामान्यीकरण: जब तक सभी प्रकार के टी प्रतिलिपि कंस्ट्रक्टर्स है

template<typename T> 
void swap(T *d1, T *d2) 
{ 
    T temp = *d1; 
    *d1 = *d2; 
    *d2 = temp; 
} 

... काम नहीं करेगा, और फिर भी संकेत दिए गए अदला-बदली की तुलना में अधिक अक्षम हो जाएगा।

+0

मुझे नहीं लगता कि आपका सादृश्य काफी काम करता है; सी ++ में 'int *' बनाम 'const int *' पर विचार करें। कॉन्स एक क्वालीफायर है जो उस प्रकार के उपयोग को प्रतिबंधित करता है जो इसे लागू करता है, प्रभावी ढंग से इसे एक अलग प्रकार में बदल देता है। लेकिन जब सी ++ को आईएल में संकलित किया जाता है, तो सीएलआई प्रकार प्रणाली में एक अलग प्रकार को परिभाषित करने के बजाय 'कॉन्स' को एक प्रकार के कस्टम संशोधक में बदल दिया जाता है। इससे पता चलता है कि भाषा में "टाइप" रनटाइम में "टाइप" से अलग है।वैसे ही 'रेफरी' सीमा के साथ आप क्या कर सकते हैं (उदाहरण के लिए, आप इसे लैम्ब्डा में कैप्चर नहीं कर सकते हैं), और यह सी # के प्रकार की प्रणाली का हिस्सा है, हालांकि सीएलआई नहीं है। –

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