बनाम रेफरी बनाम में उपयोग कब करें


383

किसी ने मुझसे दूसरे दिन पूछा जब उन्हें outइसके बजाय पैरामीटर कीवर्ड का उपयोग करना चाहिए ref। जबकि मैं (मुझे लगता है) refऔर outकीवर्ड्स के बीच के अंतर को समझते हैं (जो पहले पूछा गया है ) और सबसे अच्छा स्पष्टीकरण यह लगता है कि ref== inऔर out, कुछ (काल्पनिक या कोड) उदाहरण हैं जहां मुझे हमेशा उपयोग करना चाहिए outऔर नहीं ref

चूंकि refअधिक सामान्य है, आप कभी क्यों उपयोग करना चाहते हैं out? क्या यह सिंटैक्टिक शुगर है?


18
उपयोग किए गए एक चर को outइसे सौंपा जाने से पहले से नहीं पढ़ा जा सकता है। refयह प्रतिबंध नहीं है। तो वहीं है।
कोरी ओगबर्न

17
संक्षेप में, refके लिए / बाहर है, जबकि outएक केवल-बाहर पैरामीटर है।
टिम एस।

3
वास्तव में क्या नहीं मिलता है?
tnw

4
यह भी outचर समारोह में सौंपा जा सकता है।
कोरी ओगबर्न

धन्यवाद कोरी लेकिन मैं पहले से ही ऐसा नहीं है। मेरा कहना यह है कि इससे फायदा क्या है। वास्तव में मुझे एक उदाहरण की आवश्यकता है जो एक ऐसे परिदृश्य को दर्शाता है जहां हम कार्यक्षमता को प्राप्त करने के लिए रेफ पैरामीटर का उपयोग कर सकते हैं जो पैरामीटर और इसके विपरीत का उपयोग करके प्राप्त नहीं किया जा सकता है।
राजबीर सिंह

जवाबों:


399

outजब तक आपको आवश्यकता न हो, तब तक उपयोग करना चाहिए ref

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

इसके अलावा, यह घोषणा के पाठक या कॉल को भी दर्शाता है कि क्या प्रारंभिक मूल्य प्रासंगिक है (और संभवतः संरक्षित), या फेंक दिया गया है।

मामूली अंतर के रूप में, एक आउट पैरामीटर को प्रारंभ करने की आवश्यकता नहीं है।

इसके लिए उदाहरण out:

string a, b;
person.GetBothNames(out a, out b);

जहाँ GetBothNames दो तरीकों को परमाणु रूप से पुनः प्राप्त करने की एक विधि है, इस पद्धति से व्यवहार में परिवर्तन नहीं होगा जो कि a और b हैं। यदि कॉल हवाई में एक सर्वर पर जाती है, तो यहां से हवाई के प्रारंभिक मूल्यों की नकल बैंडविड्थ की बर्बादी है। रेफरी का उपयोग कर एक समान स्निपेट:

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

पाठकों को भ्रमित कर सकता है, क्योंकि ऐसा लगता है कि ए और बी के शुरुआती मूल्य प्रासंगिक हैं (हालांकि विधि का नाम इंगित करेगा कि वे नहीं हैं)।

इसके लिए उदाहरण ref:

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

यहां प्रारंभिक मूल्य विधि के लिए प्रासंगिक है।


5
"वास्तव में ऐसा नहीं है।" - क्या आप बेहतर समझ सकते हैं कि आपका क्या मतलब है?
पीटरचेन

3
आप refडिफ़ॉल्ट मानों के लिए उपयोग नहीं करना चाहते हैं।
C.Evenhuis

155
पोस्टरिटी के लिए: एक अन्य अंतर जो किसी ने उल्लेख किया है, जैसा कि यहां बताया गया है ; एक outपैरामीटर के लिए, कॉलिंग विधि की आवश्यकता होती है कि वे विधि रिटर्न से पहले एक मूल्य निर्दिष्ट करें। - आपको रेफरी पैरामीटर के साथ कुछ भी नहीं करना है।
ब्रिचिंस

3
@brichins आपके द्वारा बताए गए लिंक में 'टिप्पणियों (सामुदायिक परिवर्धन)' अनुभाग को देखें । यह एक त्रुटि है जो VS 2008 प्रलेखन में ठीक की गई है।
भरत राम वी।

13
@brichins नामक विधि एक मान निर्दिष्ट करने के लिए आवश्यक है, न कि कॉलिंग विधि। zverev.eugene यह वही है जो वीएस 2008 प्रलेखन में ठीक किया गया था।
सेगफॉल्ट

72

यह बताने के लिए कि पैरामीटर का उपयोग नहीं किया जा रहा है, केवल सेट करें। यह कॉलर को यह समझने में मदद करता है कि आप हमेशा पैरामीटर को इनिशियलाइज़ कर रहे हैं।

इसके अलावा, रेफ और आउट केवल मूल्य प्रकारों के लिए नहीं हैं। वे आपको उस ऑब्जेक्ट को रीसेट करने देते हैं जो एक संदर्भ प्रकार एक विधि के भीतर से संदर्भित कर रहा है।


3
+1 मैं नहीं जानता था कि इसका उपयोग संदर्भ प्रकारों के लिए भी किया जा सकता है, अच्छा स्पष्ट उत्तर, धन्यवाद
Dale

@brichins: नहीं, तुम नहीं कर सकते। outफंक्शन में एंट्री पर मापदंडों को अनसाइनड माना जाता है। आप उनके मूल्य का निरीक्षण करने में सक्षम नहीं होंगे, जब तक कि आपने पहले कुछ मूल्य निश्चित रूप से निर्दिष्ट नहीं किए हैं - जब फ़ंक्शन को कॉल किया गया था, तो पैरामीटर के पास मूल्य का उपयोग करने का कोई तरीका नहीं है।
बेन वोइगट

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

2
@ Typesา because: इसका उपयोग संदर्भ प्रकारों के साथ किया जा सकता है क्योंकि जब आप संदर्भ प्रकार के पैरामीटर में पास होते हैं, तो आप जो भी पास कर रहे हैं वह संदर्भ का मूल्य है न कि वस्तु का। तो यह अभी भी पास-बाय-वैल्यू है।
तारिक

38

आप इसमें सही हैं, शब्दार्थ, ref"इन" और "आउट" दोनों प्रकार की कार्यक्षमता outप्रदान करते हैं, जबकि केवल "आउट" कार्यक्षमता प्रदान करते हैं। विचार करने के लिए कुछ चीजें हैं:

  1. outयह आवश्यक है कि लौटने से पहले कुछ बिंदु पर, पैरामीटर MUST को स्वीकार करने की विधि, वैरिएबल के लिए एक मान निर्दिष्ट करें। आप इस पैटर्न को कुछ कुंजी / मान डेटा संग्रहण कक्षाओं में पाते हैं Dictionary<K,V>, जैसे कि आपके पास फ़ंक्शन जैसे हैं TryGetValue। यह फ़ंक्शन एक outपैरामीटर लेता है जो धारण करता है कि अगर पुनर्प्राप्त किया जाता है तो मूल्य क्या होगा। कॉल करने वाले के लिए इस फ़ंक्शन में मान को पास करने का कोई मतलब नहीं होगा , इसलिए outयह गारंटी देने के लिए उपयोग किया जाता है कि कॉल के बाद कुछ मान चर में होगा, भले ही यह "वास्तविक" डेटा नहीं है ( TryGetValueजहां के मामले में कुंजी मौजूद नहीं है)।
  2. outऔर refअंतर कोड के साथ काम करते समय मापदंडों को अलग तरह से मार्श किया जाता है

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

refकीवर्ड के साथ पासिंग का कहना है कि मूल चर और फ़ंक्शन पैरामीटर दोनों वास्तव में एक ही मेमोरी स्थान पर इंगित करेंगे। यह, फिर से, केवल असाइनमेंट शब्दार्थ को प्रभावित करता है। यदि कोई नया मान चर में से किसी एक को असाइन किया गया है, तो क्योंकि उसी मेमोरी लोकेशन के दूसरे बिंदु नए मूल्य को दूसरी तरफ परिलक्षित करेंगे।


1
ध्यान दें कि आवश्यकता है कि बुलाया विधि एक पैरामीटर के लिए एक मान प्रदान करते हैं सी # संकलक द्वारा लागू किया गया है, और अंतर्निहित IL द्वारा नहीं। इसलिए, VB.NET में लिखी गई लाइब्रेरी उस कन्वेंशन के अनुरूप नहीं हो सकती है।
जमरिनो

रेफरी की तरह लगता है वास्तव में C ++ (*) में dereferencing प्रतीक के बराबर है। C # में पास का संदर्भ C / C ++ के समतुल्य होना चाहिए जो कि डबल पॉइंटर्स (एक पॉइंटर को पॉइंटर) के रूप में संदर्भित करता है, इसलिए रेफरी को 1 पॉइंटर को डीरेंस करना चाहिए, जो संदर्भ में ऑब्जेक्ट को वास्तविक ऑब्जेक्ट की मेमोरी लोकेशन तक पहुंचने की अनुमति देता है।
आई

मैं वास्तव में सुझाव है कि एक सही होगा TryGetValueका प्रयोग करेंगे refऔर नहीं outस्पष्ट रूप से कुंजी नहीं मिल के मामले में।
नेटमैज

27

यह संकलन के संदर्भ पर निर्भर करता है (नीचे उदाहरण देखें)।

outऔर refदोनों संदर्भ द्वारा पारित चर को दर्शाते हैं, फिर refभी पारित होने से पहले चर को आरंभीकृत करने की आवश्यकता होती है, जो मार्शलिंग (इंटरोप: यूमैनेडटॉम्नट्रेडट्रांसशन या इसके विपरीत) के संदर्भ में एक महत्वपूर्ण अंतर हो सकता है

MSDN चेतावनी देता है :

संदर्भ प्रकारों की अवधारणा के संदर्भ से गुजरने की अवधारणा को भ्रमित न करें। दो अवधारणाएं समान नहीं हैं। विधि पैरामीटर को रेफरी द्वारा संशोधित किया जा सकता है, भले ही वह मूल्य प्रकार या संदर्भ प्रकार हो। संदर्भ द्वारा पारित होने पर मूल्य प्रकार की कोई बॉक्सिंग नहीं होती है।

आधिकारिक MSDN डॉक्स से:

बाहर का कीवर्ड तर्क को संदर्भ द्वारा पारित किया जाता है। यह रेफरी कीवर्ड के समान है, सिवाय इसके कि रेफ को पास होने से पहले वैरिएबल को शुरू करने की आवश्यकता होती है

रेफ कीवर्ड एक तर्क को संदर्भ द्वारा पारित करने का कारण बनता है, मूल्य द्वारा नहीं। संदर्भ से गुजरने का प्रभाव यह है कि विधि में पैरामीटर में कोई भी परिवर्तन कॉलिंग विधि में अंतर्निहित तर्क चर में परिलक्षित होता है। संदर्भ पैरामीटर का मान हमेशा अंतर्निहित तर्क चर के मूल्य के समान होता है।

हम सत्यापित कर सकते हैं कि जब तर्क दिया जाता है तो आउट और रेफ वास्तव में समान होते हैं:

CIL उदाहरण :

निम्नलिखित उदाहरण पर विचार करें

static class outRefTest{
    public static int myfunc(int x){x=0; return x; }
    public static void myfuncOut(out int x){x=0;}
    public static void myfuncRef(ref int x){x=0;}
    public static void myfuncRefEmpty(ref int x){}
    // Define other methods and classes here
}

CIL के निर्देश, अपेक्षा के अनुरूप myfuncOutऔर myfuncRefसमान हैं।

outRefTest.myfunc:
IL_0000:  nop         
IL_0001:  ldc.i4.0    
IL_0002:  starg.s     00 
IL_0004:  ldarg.0     
IL_0005:  stloc.0     
IL_0006:  br.s        IL_0008
IL_0008:  ldloc.0     
IL_0009:  ret         

outRefTest.myfuncOut:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRef:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRefEmpty:
IL_0000:  nop         
IL_0001:  ret         

nop : कोई ऑपरेशन नहीं, ldloc : स्थानीय लोड करें, stloc : ढेर स्थानीय, ldarg : लोड तर्क, bs.s : लक्ष्य करने के लिए शाखा ...।

(देखें: CIL निर्देशों की सूची )


23

नीचे कुछ नोट्स दिए गए हैं जिन्हें मैंने इस कोडप्रोजेक्ट लेख से C # आउट बनाम रेफ पर खींचा है

  1. इसका उपयोग केवल तब किया जाना चाहिए जब हम किसी फ़ंक्शन या किसी विधि से कई आउटपुट की अपेक्षा कर रहे हों। संरचनाओं पर एक विचार भी उसी के लिए एक अच्छा विकल्प हो सकता है।
  2. REF और OUT ऐसे कीवर्ड हैं जो यह बताते हैं कि कैसे कॉल करने वाले से कैली और इसके विपरीत डेटा पास किया जाता है।
  3. आरईएफ डेटा में दो तरह से गुजरता है। कॉलर से लेकर कैली और इसके विपरीत।
  4. आउट डेटा में कैली से कॉलर तक केवल एक ही रास्ता गुजरता है। इस मामले में यदि कॉलर ने कॉलली को डेटा भेजने की कोशिश की तो इसे अनदेखा / अस्वीकार कर दिया जाएगा।

यदि आप एक दृश्य व्यक्ति हैं, तो कृपया इस yourtube वीडियो को देखें, जो अंतर को व्यावहारिक रूप से प्रदर्शित करता है https://www.youtube.com/watch?v=lYdcY5zulXA

नीचे की छवि अंतर को अधिक नेत्रहीन रूप से दिखाती है

सी # आउट बनाम रेफ


1
one-way, two-wayये शब्द का दुरुपयोग किया जा सकता है। वे वास्तव में दो-तरफा हैं, हालांकि उनके वैचारिक व्यवहार मापदंडों के संदर्भ और मूल्यों पर भिन्न होते हैं
ibubi

17

refयदि आपको पैरामीटर को पढ़ने और लिखने की योजना है, तो आपको इसका उपयोग करने की आवश्यकता है । outयदि आपको केवल लिखने की योजना है तो आपको इसका उपयोग करने की आवश्यकता है । वास्तव में, outयह तब होता है जब आपको एक से अधिक रिटर्न वैल्यू की आवश्यकता होगी, या जब आप आउटपुट के लिए सामान्य रिटर्न मैकेनिज्म का उपयोग नहीं करना चाहते हैं (लेकिन यह दुर्लभ होना चाहिए)।

ऐसे भाषा मैकेनिक हैं जो इन उपयोग मामलों की सहायता करते हैं। Refमानकों को एक विधि में पास करने से पहले आरंभीकृत किया जाना चाहिए (इस तथ्य पर जोर देते हुए कि वे पढ़े-लिखे हैं), और outमान को असाइन किए जाने से पहले मापदंडों को नहीं पढ़ा जा सकता है, और गारंटी दी जाती है कि वे अंत में लिखे गए हैं विधि (इस तथ्य पर जोर देते हुए कि वे केवल लिखे गए हैं)। इन सिद्धांतों के विपरीत होने से संकलन-समय में त्रुटि होती है।

int x;
Foo(ref x); // error: x is uninitialized

void Bar(out int x) {}  // error: x was not written to

उदाहरण के लिए, int.TryParseएक रिटर्न देता है boolऔर एक out intपैरामीटर स्वीकार करता है :

int value;
if (int.TryParse(numericString, out value))
{
    /* numericString was parsed into value, now do stuff */
}
else
{
    /* numericString couldn't be parsed */
}

यह उस स्थिति का एक स्पष्ट उदाहरण है जहां आपको दो मानों का आउटपुट करने की आवश्यकता होती है: संख्यात्मक परिणाम और क्या रूपांतरण सफल था या नहीं। सीएलआर के लेखकों ने outयहां चुनने का फैसला किया क्योंकि उन्हें इस बात की परवाह नहीं है कि intपहले क्या हो सकता था।

के लिए ref, आप पर देख सकते हैं Interlocked.Increment:

int x = 4;
Interlocked.Increment(ref x);

Interlocked.Incrementपरमाणु मूल्य बढ़ाता है x। चूंकि आपको xइसे बढ़ाने के लिए पढ़ने की आवश्यकता है , यह एक ऐसी स्थिति है जहां refअधिक उपयुक्त है। आप इसके बारे में पूरी तरह से परवाह करते हैं कि xइसे पारित करने से पहले क्या था Increment

C # के अगले संस्करण में, outमापदंडों में परिवर्तनशील घोषित करना भी संभव होगा , उनके आउटपुट-ओनली नेचर पर और भी अधिक जोर देते हुए:

if (int.TryParse(numericString, out int value))
{
    // 'value' exists and was declared in the `if` statement
}
else
{
    // conversion didn't work, 'value' doesn't exist here
}

आपकी प्रतिक्रिया के लिए धन्यवाद zneak लेकिन क्या आप मुझे समझा सकते हैं कि मैं एक पैरामीटर को पढ़ने और लिखने के लिए उपयोग क्यों नहीं कर सका?
राजबीर सिंह

@ राजबीरसिंह, क्योंकि outमापदंडों को आवश्यक रूप से आरंभ नहीं किया गया है, इसलिए कंपाइलर आपको एक outपैरामीटर से पढ़ने नहीं देगा, जब तक कि आपने इसे कुछ नहीं लिखा हो।
18

zneak, मैं आपसे सहमत हूं। लेकिन नीचे उदाहरण में एक आउट पैरामीटर को पढ़ने और लिखने के रूप में इस्तेमाल किया जा सकता है: स्ट्रिंग नाम = "myName"; निजी शून्य आउटमैथोड (स्ट्रिंग नाम के बाहर) {अगर (nameOut == "myName") {nameOut = "राजबीर सिंह आउट पद्धति में"; }}
राजबीर सिंह 19

1
@ राजबीरसिंह, आपका उदाहरण संकलन नहीं है। आप nameOutअपने ifबयान में नहीं पढ़ सकते क्योंकि इसे पहले कुछ भी नहीं सौंपा गया था।
19

धन्यवाद @zneak तुम पूरी तरह ठीक हो। यह संकलन नहीं है। मेरी मदद के लिए बहुत बहुत धन्यवाद और अब यह मेरे लिए समझ में आता है :)
राजबीर सिंह

7

outअधिक बाधा संस्करण है ref

एक विधि निकाय में, आपको outविधि छोड़ने से पहले सभी मापदंडों को निर्दिष्ट करना होगा । इसके अलावा एक outपैरामीटर को दिए गए मानों को अनदेखा किया जाता है, जबकि refउन्हें असाइन करने की आवश्यकता होती है।

तो outआपको करने की अनुमति देता है:

int a, b, c = foo(out a, out b);

जहां refऔर बी को सौंपा जाना चाहिए।


कुछ भी हो, outकम विवश संस्करण है। ref"पूर्वसर्ग: चर निश्चित रूप से असाइन किया गया है, पोस्टकॉन्डिशन: चर निश्चित रूप से सौंपा गया है", जबकि outकेवल `पोस्टकॉन्डिशन: चर निश्चित रूप से सौंपा गया है" (और जैसा कि अपेक्षित है, कम पूर्व शर्त के साथ एक फ़ंक्शन कार्यान्वयन की आवश्यकता है)
बेन Voigt

@BenVoigt: लगता है कि आप किस दिशा में देख रहे हैं निर्भर करता है :) मुझे लगता है कि मैं लचीलेपन (?) के संदर्भ में बाधा का मतलब है।
लेप्पी

7

यह कैसे लगता है:

बाहर = केवल इनिशियलाइज़ / एक पैरामीटर (पैरामीटर रिक्त होना ही चाहिए) इसे वापस भरने बाहर सादे

रेफरी = संदर्भ, मानक पैरामीटर (शायद मूल्य के साथ), लेकिन समारोह में यह modifiy कर सकते हैं।


बाहर पैरामीटर चर एक मान प्राप्त कर सकते हैं, इससे पहले कि आप इसे एक विधि से पास करें।
बेन्स वेर्ट

6

आप outदो संदर्भों में प्रासंगिक कीवर्ड का उपयोग कर सकते हैं (प्रत्येक विस्तृत जानकारी के लिए एक लिंक है), एक पैरामीटर संशोधक के रूप में या इंटरफेस और प्रतिनिधियों में सामान्य प्रकार के पैरामीटर घोषणाओं में। यह विषय पैरामीटर संशोधक पर चर्चा करता है, लेकिन आप सामान्य प्रकार के पैरामीटर घोषणाओं की जानकारी के लिए इस अन्य विषय को देख सकते हैं।

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

class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}

यद्यपि outतर्क के रूप में पारित चर को पारित होने से पहले आरंभीकृत नहीं किया जाता है, विधि के वापस आने से पहले एक मूल्य निर्दिष्ट करने के लिए बुलाया विधि की आवश्यकता होती है।

यद्यपि कीवर्ड refऔर outकीवर्ड अलग-अलग रन-टाइम व्यवहार का कारण बनते हैं, लेकिन उन्हें संकलन समय पर विधि हस्ताक्षर का हिस्सा नहीं माना जाता है। इसलिए, यदि केवल एक विधि एक refतर्क लेती है और दूसरा एक outतर्क लेता है , तो विधियों को अतिभारित नहीं किया जा सकता है। निम्न कोड, उदाहरण के लिए, संकलन नहीं करेगा: C #

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

ओवरलोडिंग किया जा सकता है, हालांकि, अगर एक विधि एक तर्क refया outतर्क लेती है और दूसरा इस तरह से उपयोग नहीं करता है: C #

class OutOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) { i = 5; }
}

गुण चर नहीं हैं और इसलिए उन्हें outमापदंडों के रूप में पारित नहीं किया जा सकता है ।

पासिंग एरे के बारे में जानकारी के लिए, पासिंग एरे का उपयोग करना refऔर out(सी # प्रोग्रामिंग गाइड) देखें।

आप निम्न प्रकार के तरीकों के लिए कीवर्ड refऔर outकीवर्ड का उपयोग नहीं कर सकते हैं :

Async methods, which you define by using the async modifier.

Iterator methods, which include a yield return or yield break statement.

उदाहरण

एक outविधि की घोषणा करना उपयोगी है जब आप कई मान वापस करने के लिए एक विधि चाहते हैं। निम्न उदाहरण outएकल विधि कॉल के साथ तीन चर वापस करने के लिए उपयोग करता है। ध्यान दें कि तीसरा तर्क निरर्थक है। यह मानों को वैकल्पिक रूप से वापस करने के तरीकों को सक्षम बनाता है। सी#

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}

6

कैसे उपयोग करने के लिए inया outया refसी # में?

  • सभी कीवर्ड की C#कार्यक्षमता समान है लेकिन कुछ सीमाओं के साथ ।
  • in तर्कों को विधि द्वारा संशोधित नहीं किया जा सकता है।
  • ref तर्कों को संशोधित किया जा सकता है।
  • ref कॉलर द्वारा उपयोग किए जाने से पहले इसे आरंभ किया जाना चाहिए इसे विधि में पढ़ा और अपडेट किया जा सकता है।
  • out कॉलगर्ल द्वारा तर्क को संशोधित किया जाना चाहिए।
  • out तर्कों को विधि में आरंभीकृत किया जाना चाहिए
  • inएक विधि कॉल में पारित होने से पहले तर्क के रूप में पारित चर को आरंभ किया जाना चाहिए। हालाँकि, कॉल विधि मान असाइन नहीं कर सकती या तर्क को संशोधित नहीं कर सकती है।

आप उपयोग नहीं कर सकते in, refऔर outतरीकों में से निम्नलिखित प्रकार के लिए कीवर्ड:

  • Async विधियाँ , जिन्हें आप asyncसंशोधक का उपयोग करके परिभाषित करते हैं।
  • Iterator विधियाँ , जिनमें एक yield returnया yield breakकथन शामिल है।

5

ओपी की टिप्पणी पर स्पष्ट करने के लिए कि रेफ एंड आउट का उपयोग "विधि के बाहर घोषित मूल्य या संरचना का संदर्भ" है, जो पहले ही गलत तरीके से स्थापित हो चुका है।

StringBuilder पर रेफरी के उपयोग पर विचार करें, जो एक संदर्भ प्रकार है:

private void Nullify(StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// Hi Guy

जैसा कि इसके लिए अपील की गई है:

private void Nullify(ref StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(ref sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// NullReferenceException

4

विधि के पास जाने से पहले रेफ के रूप में पारित एक तर्क को प्रारंभ किया जाना चाहिए, जबकि एक विधि को पारित करने से पहले पैरामीटर को बाहर करने की आवश्यकता नहीं है।


4

आप कभी भी उपयोग क्यों करना चाहते हैं?

दूसरों को यह बताने के लिए कि चर को प्रारंभिक विधि से कहा जाएगा, जब यह विधि कहा जाता है!

जैसा कि ऊपर उल्लेख किया गया है: "एक आउट पैरामीटर के लिए, कॉलिंग विधि को रिटर्न के पहले एक मान निर्दिष्ट करना आवश्यक है ।"

उदाहरण:

Car car;
SetUpCar(out car);
car.drive();  // You know car is initialized.

4

मूल रूप से दोनों refऔर outतरीकों के बीच वस्तु / मूल्य पारित करने के लिए

बाहर का कीवर्ड तर्क को संदर्भ द्वारा पारित किया जाता है। यह रेफरी कीवर्ड की तरह है, सिवाय इसके कि रेफ को आवश्यकता होती है कि वेरिएबल को शुरू होने से पहले इसे शुरू किया जाए।

out : तर्क को आरंभीकृत नहीं किया गया है और इसे विधि में आरंभीकृत किया जाना चाहिए

ref : तर्क पहले से ही आरंभिक है और इसे विधि में पढ़ा और अद्यतन किया जा सकता है।

संदर्भ-प्रकारों के लिए "रेफ" का उपयोग क्या है?

आप दिए गए संदर्भ को एक अलग उदाहरण में बदल सकते हैं।

क्या तुम्हें पता था?

  1. हालाँकि, रेफ और आउट कीवर्ड अलग-अलग रन-टाइम व्यवहार का कारण होते हैं, लेकिन उन्हें संकलन समय पर विधि हस्ताक्षर का हिस्सा नहीं माना जाता है। इसलिए, यदि कोई अंतर केवल एक रेफरी तर्क के लिए लेता है और दूसरा आउट तर्क लेता है, तो विधियों को ओवरलोड नहीं किया जा सकता है।

  2. आप निम्न प्रकार के तरीकों के लिए रेफ और आउट कीवर्ड का उपयोग नहीं कर सकते हैं:

    • Async विधियाँ, जिन्हें आप async संशोधक का उपयोग करके परिभाषित करते हैं।
    • Iterator विधियाँ, जिसमें एक उपज वापसी या उपज विराम कथन शामिल हैं।
  3. गुण परिवर्तनीय नहीं हैं और इसलिए इन्हें मापदंडों के रूप में पारित नहीं किया जा सकता है।


4

C # 7 के बारे में अतिरिक्त नोट्स:
C # 7 में वेरिएबल्स का उपयोग करने की कोई आवश्यकता नहीं है। तो इस तरह एक कोड:

public void PrintCoordinates(Point p)
{
  int x, y; // have to "predeclare"
  p.GetCoordinates(out x, out y);
  WriteLine($"({x}, {y})");
}

इस तरह लिखा जा सकता है:

public void PrintCoordinates(Point p)
{
  p.GetCoordinates(out int x, out int y);
  WriteLine($"({x}, {y})");
}

स्रोत: C # 7 में नया क्या है


4

फिर भी एक अच्छे सारांश की आवश्यकता महसूस होती है, यही मैं साथ आया हूं।

सारांश,

जब हम फ़ंक्शन के अंदर होते हैं , तो यह है कि हम चर डेटा एक्सेस कंट्रोल को कैसे निर्दिष्ट करते हैं ,

in = आर

out = R से पहले W होना चाहिए

ref = आर + डब्ल्यू


स्पष्टीकरण,

in

फ़ंक्शन केवल उस चर को पढ़ सकता है ।

out

चर पहले क्योंकि initialised नहीं किया जाना चाहिए,
समारोह MUST लिखें इससे पहले कि यह करने के लिए पढ़ें

ref

फ़ंक्शन उस चर को पढ़ / पढ़ सकता है ।


इसका नाम ऐसा क्यों रखा गया है?

डेटा को संशोधित करने पर ध्यान केंद्रित करना,

in

डेटा केवल (इन) फ़ंक्शन दर्ज करने से पहले सेट किया जाना चाहिए।

out

डेटा को केवल (आउट) फ़ंक्शन को छोड़ने से पहले सेट किया जाना चाहिए।

ref

डेटा (इन) फ़ंक्शन दर्ज करने से पहले सेट किया जाना चाहिए।
कार्य को छोड़ने (आउट) करने से पहले डेटा सेट किया जा सकता है।


हो सकता है (in / out / Ref) का नाम बदलकर (r / wr / rw) कर दिया जाए। या नहीं, में / बाहर एक अच्छा रूपक है।
टिंकर

0

यह ध्यान दिया जाना चाहिए कि C # ver 7.2 केin रूप में एक मान्य कीवर्ड है :

पैरामीटर संशोधक C # 7.2 और बाद में उपलब्ध है। पिछले संस्करण कंपाइलर त्रुटि उत्पन्न करते हैं CS8107 ("फ़ीचर 'आसानी से संदर्भ' C # 7.0 में उपलब्ध नहीं है। कृपया भाषा संस्करण 7.2 या अधिक का उपयोग करें।") संकलक भाषा संस्करण को कॉन्फ़िगर करने के लिए, C # भाषा संस्करण का चयन करें देखें।

...

कीवर्ड में संदर्भ के आधार पर तर्क दिए जाते हैं। यह तर्क के लिए औपचारिक पैरामीटर को एक उपनाम बनाता है, जिसे एक चर होना चाहिए। दूसरे शब्दों में, पैरामीटर पर कोई भी ऑपरेशन तर्क पर किया जाता है। यह रेफ या आउट कीवर्ड की तरह है, सिवाय इसके कि तर्कों को संशोधित विधि द्वारा संशोधित नहीं किया जा सकता है। जबकि रीफ तर्कों को संशोधित किया जा सकता है, आउट तर्कों को तथाकथित विधि द्वारा संशोधित किया जाना चाहिए, और उन संशोधनों को कॉलिंग संदर्भ में देखा जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.