'Ref' और 'out' कीवर्ड में क्या अंतर है?


891

मैं एक फंक्शन बना रहा हूँ जहाँ मुझे एक ऑब्जेक्ट पास करने की आवश्यकता है ताकि इसे फंक्शन द्वारा संशोधित किया जा सके। के बीच क्या अंतर है:

public void myFunction(ref MyClass someClass)

तथा

public void myFunction(out MyClass someClass)

मुझे किसका उपयोग करना चाहिए और क्यों?


69
आप: मुझे एक वस्तु पारित करने की आवश्यकता है ताकि इसे संशोधित किया जा सके ऐसा लगता है कि यहMyClass एक classप्रकार होगा, अर्थात एक संदर्भ प्रकार। उस स्थिति में, आपके द्वारा पास की गई वस्तु myFunctionको बिना ref/ outकीवर्ड के भी संशोधित किया जा सकता है । myFunctionएक नया संदर्भ प्राप्त करेगा जो एक ही वस्तु को इंगित करता है , और यह उसी वस्तु को संशोधित कर सकता है जितना वह चाहता है। जितना अंतर refकीवर्ड करेगा, उसे उतने ही ऑब्जेक्ट के लिए एक ही संदर्भ myFunctionप्राप्त होगा । यह तभी महत्वपूर्ण होगा जब किसी अन्य वस्तु को इंगित करने के लिए संदर्भ को बदल दिया जाए । myFunction
जेपी स्टिग नील्सन

3
मैं यहाँ भ्रमित करने वाले उत्तरों की मात्रा से हैरान हूँ, जब @ AnthonyKolesov काफी परफेक्ट है।
ओ ० '।

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

यहाँ उदाहरण के साथ समझाया गया है यह अधिक समझ में आता है :) dotnet-tricks.com/Tutorial/csharp/…
प्रेजेथ गॉडेज

2
@ JeppeStigNielsen की टिप्पणी, तकनीकी रूप से, ओपी के वास्तविक प्रश्न का सही (केवल) सही उत्तर है। किसी ऑब्जेक्ट को किसी विधि में पास करने के लिए ताकि विधि ऑब्जेक्ट को संशोधित कर सके , बस मान द्वारा विधि में ऑब्जेक्ट को (संदर्भ) पास करें। ऑब्जेक्ट लॉजिक के माध्यम से विधि के भीतर ऑब्जेक्ट को बदलना मूल ऑब्जेक्ट को संशोधित करता है , भले ही विधि में अपना अलग चर हो (जो एक ही ऑब्जेक्ट को संदर्भित करता है)।
डेविड आर ट्रिब्बल

जवाबों:


1158

refसंकलक को बताता है कि फ़ंक्शन में प्रवेश करने से पहले ऑब्जेक्ट को इनिशियलाइज़ किया जाता है, जबकि outकंपाइलर को बताता है कि फ़ंक्शन के अंदर ऑब्जेक्ट को इनिशियलाइज़ किया जाएगा।

तो जबकि refदो तरह से है, outकेवल बाहर है।


269
एक और खास बात यह है कि फंक्शन को आउट पैरामीटर को असाइन करना है। इसे बिना बताए छोड़ने की अनुमति नहीं है।
डेनियल ईयरविकर

7
क्या 'Ref' केवल मूल्य प्रकार पर लागू होता है? चूंकि संदर्भ प्रकार हमेशा रेफरी द्वारा पास किया जाता है।
दोषपूर्ण

3
हाँ। मूल्य प्रकार सहित संरचनाएं
रूण ग्रिमस्टैड

17
@ दोष: नहीं, रेफ न केवल मूल्य प्रकारों पर लागू होता है। Ref / out C / C ++ में पॉइंटर्स की तरह हैं, वे ऑब्जेक्ट की मेमोरी लोकेशन (अप्रत्यक्ष रूप से C #) में डायरेक्ट ऑब्जेक्ट के बजाय डील करते हैं।
thr

52
@faulty: काउंटरिंटुइवली, संदर्भ प्रकारों को हमेशा C # में मान द्वारा पारित किया जाता है, जब तक कि आप रेफ स्पेसियर का उपयोग नहीं करते हैं। यदि आप myval = somenewval सेट करते हैं, तो प्रभाव केवल उस फ़ंक्शन स्कोप में होता है। रेफरी कीवर्ड आपको myenewal को इंगित करने के लिए परिवर्तन करने की अनुमति देगा।
जेसनट्रू

534

refसंशोधक का मतलब है कि:

  1. मान पहले से सेट है और
  2. विधि इसे पढ़ और संशोधित कर सकती है।

outसंशोधक का मतलब है कि:

  1. मान सेट नहीं है और इसे सेट होने तक विधि द्वारा पढ़ा नहीं जा सकता है।
  2. लौटने से पहले विधि को सेट करना होगा

30
यह उत्तर सबसे स्पष्ट और संक्षिप्त रूप से उन प्रतिबंधों की व्याख्या करता है जो कंपाइलर रेफ कीवर्ड के विपरीत आउट कीवर्ड का उपयोग करते समय करता है।
डॉ। विली के अपरेंटिस

5
MSDN से: एक रेफ पैरामीटर को उपयोग करने से पहले आरंभीकृत किया जाना चाहिए, जबकि एक आउट पैरामीटर को पारित होने से पहले स्पष्ट रूप से आरंभीकृत नहीं किया जाना चाहिए और किसी भी पिछले मान को अनदेखा नहीं किया जाना चाहिए।
शिव कुमार

1
इसके साथ out, क्या इसे विधि के भीतर सेट किया जा सकता है, इससे पहले कि यह विधि द्वारा निर्धारित किया गया हो, अगर इसे विधि कहा जाता है, तो इसे पहले इनिशियलाइज़ किया गया है? मेरा मतलब है, क्या कॉल विधि पढ़ सकती है कि कॉलिंग विधि क्या तर्क के रूप में इसे पारित कर देती है?
पैंजरक्रिस

3
Panzercrisis, "आउट" के लिए, बुलाया विधि पढ़ सकती है यदि यह पहले से ही सेट है। लेकिन इसे फिर से सेट करना होगा।
रोबर्ट जेबाकुमार 2

146

मान लीजिए कि टीपीएस रिपोर्ट के बारे में मेमो के बारे में पीटर के क्यूबिकल में डोम दिखाता है।

यदि डोम एक रेफरी तर्क थे, तो उनके पास मेमो की एक मुद्रित प्रति होगी।

यदि डोम एक आउट तर्क था, तो वह पीटर को उसके साथ लेने के लिए मेमो की एक नई प्रति प्रिंट करेगा।


54
रेफ डोम ने पेंसिल में रिपोर्ट लिखी होगी ताकि पीटर इसे संशोधित कर सके
डेबस्टर

6
@ डिएबस्टर, आप जानते हैं कि रूपक ने कभी भी आपके साथ कुछ नहीं किया, आपको ऐसा क्यों करना चाहिए? ;)
माइकल ब्लैकबर्न 16

21
मनोरंजक अभी तक शिक्षित, stackoverflow इस तरह अधिक पदों की जरूरत है
फ्रैंक Visaggio

2
बस अगर किसी को यह उत्तर केवल आधा-अजीब लगता है, तो कृपया "ऑफिस स्पेस" फिल्म देखें।
डिस्प्लेनाम

डोम एंड पीटर्स बॉस बीहिन डोम के रूप में खड़ा होगा (बाहर तर्क के रूप में), जब तक पीटर प्रिंटआउट को हाथ नहीं लगाता, दोनों को काम करने के लिए मजबूर किया जाता है
पैट्रिक

57

मैं एक स्पष्टीकरण में अपना हाथ आज़माने जा रहा हूँ:

मुझे लगता है कि हम समझते हैं कि मूल्य प्रकार सही कैसे काम करते हैं? मान प्रकार हैं (इंट, लॉन्ग, स्ट्रक्चर इत्यादि)। जब आप उन्हें रेफरी के बिना किसी फ़ंक्शन में भेजते हैं तो यह डेटा को कॉपी करता है । फ़ंक्शन में उस डेटा के लिए कुछ भी करना केवल कॉपी को प्रभावित करता है, मूल को नहीं। रेफरी कमांड ACTUAL डेटा भेजता है और कोई भी परिवर्तन फ़ंक्शन के बाहर डेटा को प्रभावित करेगा।

भ्रामक भाग पर ठीक है, संदर्भ प्रकार:

एक संदर्भ प्रकार बनाएं:

List<string> someobject = new List<string>()

जब आप someobject को नया करते हैं , तो दो भाग बनते हैं:

  1. मेमोरी का वह ब्लॉक जो किसी अवस्थिति के लिए डेटा रखता है ।
  2. डेटा के उस ब्लॉक में एक संदर्भ (पॉइंटर)।

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

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

एक ही वस्तु की ओर इशारा करते हुए दो संदर्भ। यदि आप रेफरेंस 2 का उपयोग करके किसी प्रॉपर्टी को संशोधित करते हैं तो यह रेफरेंस 1 द्वारा बताए गए उसी डेटा को प्रभावित करेगा।

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

यदि आप संदर्भ 2 को शून्य करते हैं या इसे नए डेटा पर इंगित करते हैं तो यह संदर्भ 1 को प्रभावित नहीं करेगा और न ही डेटा संदर्भ 1 को इंगित करता है।

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

अब क्या होता है जब आप किसी विधि द्वारा रेफ्यूज को भेजते हैं ? वास्तविक संदर्भ को someobject विधि करने के लिए भेजा जाता है। तो अब आपके पास डेटा का केवल एक संदर्भ है:

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

लेकिन इसका क्या मतलब है? यह बिल्कुल वैसा ही काम करता है जैसे कोई दो बिंदुओं को छोड़कर रेफ द्वारा नहीं भेजा जाता है:

1) जब आप मेथड के अंदर के रेफरेंस को शून्य कर देते हैं, तो यह मेथड के बाहर वाले को शून्य कर देगा।

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2) अब आप एक पूरी तरह से अलग डेटा स्थान के संदर्भ को इंगित कर सकते हैं और फ़ंक्शन के बाहर का संदर्भ अब नए डेटा स्थान को इंगित करेगा।

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true

आप सब के बाद (रेफरी मामले में) डेटा के लिए केवल एक संदर्भ है, लेकिन इसके लिए दो उपनाम हैं। सही?
सादिक

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

1
गजब का। क्या आप outकीवर्ड के लिए समान व्याख्या कर सकते हैं ?
आसिफ मुश्ताक

28

रेफरी अंदर और बाहर है

outजहाँ भी आपकी आवश्यकताओं के लिए यह आवश्यक हो, आपको वरीयता में उपयोग करना चाहिए ।


काफी नहीं, जैसा कि स्वीकार किए जाते हैं उत्तर के रूप में अगर दिशात्मक और बेकार मूल्य-अनदेखी अनदेखी अगर वापस बाहर पारित नहीं।
केनी

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

(BTW मैं मूल्य प्रकार, संदर्भ प्रकार, संदर्भ से गुजर रहा हूं, मान से गुजर रहा हूं, COM और C ++ से आपको अपने स्पष्टीकरण में उन अवधारणाओं का संदर्भ बनाने के लिए उपयोगी होना चाहिए)
रूबेन बार्टेलिंक

1
ऑब्जेक्ट संदर्भ मूल्य द्वारा पारित किए जाते हैं ("रेफरी" या "आउट" कीवर्ड का उपयोग करते हुए)। आईडी नंबर के रूप में वस्तुओं के बारे में सोचो। यदि कोई वर्ग चर "ऑब्जेक्ट # 1943" रखता है और कोई उस वैरिएबल को एक रुटीन के मान से पास करता है, तो वह रुटीन ऑब्जेक्ट # 1943 में बदलाव कर सकता है, लेकिन यह "ऑब्जेक्ट # 1943" के अलावा किसी अन्य चीज को वैरिएबल पॉइंट नहीं बना सकता है। यदि चर को संदर्भ द्वारा पारित किया गया था, तो दिनचर्या चर बिंदु को "ऑब्जेक्ट # 5441" बना सकती है।
सुपरकैट

1
@ सुपरकैट: मैं रेफरी वैल (और इस फॉलोअप एनॉलॉजी) के आपके स्पष्टीकरण को पसंद करता हूं। मुझे लगता है कि केनी को वास्तव में इसके बारे में समझाने की जरूरत नहीं है, (अपेक्षाकृत) भ्रामक है क्योंकि उनकी टिप्पणियां थीं। मेरी इच्छा है कि हम सभी इन गॉडडैम टिप्पणियों को हटा सकते हैं, हालांकि वे सभी को भ्रमित कर रहे हैं। इस सभी बकवास का मूल कारण यह प्रतीत होता है कि केनी ने मेरे उत्तर को गलत बताया और अभी तक एक भी शब्द को इंगित नहीं किया है जिसे जोड़ा / हटाया / प्रतिस्थापित किया जाना चाहिए। हम में से किसी ने भी चर्चा से कुछ भी नहीं सीखा है जो हम पहले से ही जानते हैं और दूसरे उत्तर में उत्थान की एक बड़ी संख्या है।
बारबेलिंक

18

बाहर:

C # में, एक विधि केवल एक मान लौटा सकती है। यदि आप एक से अधिक मूल्य वापस करना चाहते हैं, तो आप आउट कीवर्ड का उपयोग कर सकते हैं। बाहर के संशोधक रिटर्न-बाय-रेफरेंस के रूप में लौटते हैं। सबसे सरल उत्तर यह है कि "आउट" कीवर्ड का उपयोग विधि से मान प्राप्त करने के लिए किया जाता है।

  1. आपको कॉलिंग फ़ंक्शन में मान को इनिशियलाइज़ करने की आवश्यकता नहीं है।
  2. आपको कॉल किए गए फ़ंक्शन में मान असाइन करना होगा, अन्यथा कंपाइलर एक त्रुटि की रिपोर्ट करेगा।

संदर्भ:

C # में, जब आप कोई मान टाइप करते हैं जैसे कि int, float, double आदि तो विधि पैरामीटर के तर्क के रूप में, इसे मान द्वारा पास किया जाता है। इसलिए, यदि आप पैरामीटर मान को संशोधित करते हैं, तो यह विधि कॉल में तर्क को प्रभावित नहीं करता है। लेकिन अगर आप "रेफरी" कीवर्ड के साथ पैरामीटर को चिह्नित करते हैं, तो यह वास्तविक चर में प्रतिबिंबित होगा।

  1. फ़ंक्शन को कॉल करने से पहले आपको चर को इनिशियलाइज़ करना होगा।
  2. विधि में रेफरी पैरामीटर के लिए कोई मान निर्दिष्ट करना अनिवार्य नहीं है। यदि आप मान नहीं बदलते हैं, तो इसे "रेफ" के रूप में चिह्नित करने की क्या आवश्यकता है?

"C # में, एक विधि केवल एक मान लौटा सकती है। यदि आप एक से अधिक मान लौटना चाहते हैं, तो आप आउट कीवर्ड का उपयोग कर सकते हैं।" हम वापसी मूल्य के लिए "रेफ" का भी उपयोग कर सकते हैं। तो अगर हम एक विधि से कई मान वापस करना चाहते हैं तो रेफ और आउट दोनों का उपयोग कर सकते हैं?
नेड

1
C # 7 में आप ValueTuples के साथ कई मान वापस कर सकते हैं।
इमान बहरामपुर

13

कुत्ते का विस्तार, बिल्ली उदाहरण। रेफरी के साथ दूसरी विधि कॉलर द्वारा संदर्भित ऑब्जेक्ट को बदल देती है। इसलिए "बिल्ली" !!!

    public static void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog". 
        Bar(ref myObject);
        Console.WriteLine(myObject.Name); // Writes "Cat". 
    }

    public static void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

    public static void Bar(ref MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

8

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

उदाहरण:

public void Foo()
{
    MyClass myObject = new MyClass();
    myObject.Name = "Dog";
    Bar(myObject);
    Console.WriteLine(myObject.Name); // Writes "Cat".
}

public void Bar(MyClass someObject)
{
    someObject.Name = "Cat";
}

जब तक आप एक ऐसी कक्षा में पास हो जाते हैं, जिसका आपको उपयोग नहीं करना है, refयदि आप अपने तरीके के अंदर की वस्तु को बदलना चाहते हैं।


5
यह तभी काम करता है जब कोई नई वस्तु बनाई और वापस न की जाए। जब एक नई वस्तु बनाई जाती है, तो पुरानी वस्तु का संदर्भ खो जाएगा।
Etsuba

8
यह गलत है - निम्नलिखित का प्रयास करें: निष्पादन समाप्त करने के someObject = nullलिए जोड़ें Bar। आपका कोड ठीक चलेगा क्योंकि केवल Barउदाहरण के संदर्भ को शून्य कर दिया गया था। अब बदल Barकर Bar(ref MyClass someObject)फिर से क्रियान्वित करें - आपको उदाहरण के लिए एक संदर्भ मिल जाएगा NullReferenceExceptionक्योंकि इसे Fooभी शून्य कर दिया गया है।
कीथ

8

refऔर outमतभेदों को छोड़कर समान व्यवहार करें।

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

8

उन लोगों के लिए जो उदाहरण के द्वारा सीखते हैं (मेरे जैसे) यहाँ एंथोनी कोलेसोव कह रहे हैं

मैंने बिंदु को दर्शाने के लिए रेफ, आउट और अन्य के कुछ न्यूनतम उदाहरण बनाए हैं। मैं सर्वोत्तम प्रथाओं को कवर नहीं कर रहा हूं, मतभेदों को समझने के लिए सिर्फ उदाहरण।

https://gist.github.com/2upmedia/6d98a57b68d849ee7091


6

"बेकर, नानबाई"

ऐसा इसलिए क्योंकि "बेकर" को इंगित करने के लिए आपका पहला स्ट्रिंग-संदर्भ बदलता है। संदर्भ बदलना संभव है क्योंकि आपने इसे रेफ कीवर्ड (=> स्ट्रिंग के संदर्भ में संदर्भ) के माध्यम से पारित किया है। दूसरी कॉल को स्ट्रिंग के संदर्भ की एक प्रति मिलती है।

स्ट्रिंग पहली बार में किसी प्रकार की विशेष दिखती है। लेकिन स्ट्रिंग सिर्फ एक संदर्भ वर्ग है और यदि आप परिभाषित करते हैं

string s = "Able";

तब s एक स्ट्रिंग क्लास का संदर्भ होता है जिसमें "Able" टेक्स्ट होता है! उसी चर के माध्यम से एक और असाइनमेंट

s = "Baker";

मूल स्ट्रिंग को नहीं बदलता है लेकिन सिर्फ एक नया उदाहरण बनाता है और उस उदाहरण को इंगित करता है!

आप इसे निम्न छोटे कोड उदाहरण के साथ आज़मा सकते हैं:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

आप क्या उम्मीद करते हैं? आपको जो मिलेगा वह अभी भी "सक्षम" है क्योंकि आप मूल संदर्भ में s2 बिंदुओं के लिए संदर्भ को दूसरे उदाहरण में सेट करते हैं।

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


1
बिल्कुल सही। इसलिए यह कहना कड़ाई से सच नहीं है "चूंकि आप एक संदर्भ प्रकार (एक वर्ग) में पास कर रहे हैं, इसलिए उपयोग रेफरी की आवश्यकता नहीं है"।
पॉल मिचेल

सिद्धांत रूप में ऐसा कहना सही है क्योंकि उन्होंने लिखा है "ताकि इसे संशोधित किया जा सके" जो कि तार पर संभव नहीं है। लेकिन अपरिवर्तनीय वस्तुओं के कारण "रेफ" और "आउट" संदर्भ प्रकारों के लिए भी बहुत उपयोगी हैं! (.Net में बहुत सारी अपरिवर्तनीय कक्षाएं हैं!)
mmmmmmmm

हाँ तुम सही हो। मैंने आवेश जैसी अपरिवर्तनीय वस्तुओं के बारे में नहीं सोचा था क्योंकि अधिकांश वस्तु परस्पर हैं।
एल्बिक

1
खैर, यह LQP में देखने के लिए एक निश्चित जवाब है, सुनिश्चित करने के लिए; इसके साथ कोई गलत बात नहीं है, सिवाय इसके कि यह एक और टिप्पणी के लिए एक लंबी और गहन प्रतिक्रिया प्रतीत होती है (क्योंकि मूल प्रश्न में इसके किसी भी संशोधन में सक्षम और बेकर का उल्लेख नहीं है), जैसे कि यह एक मंच था। मुझे लगता है कि वास्तव में अभी तक वापस तरह से हल नहीं किया गया था जब।
नाथन टग्गी

6

रेफ का अर्थ है कि रेफ पैरामीटर में मान पहले से सेट है, विधि इसे पढ़ और संशोधित कर सकती है। रेफ कीवर्ड का उपयोग करना यह कहने के समान है कि कॉल करने वाला पैरामीटर के मूल्य को शुरू करने के लिए जिम्मेदार है।


बाहर संकलक को बताता है कि ऑब्जेक्ट का आरंभीकरण फ़ंक्शन की जिम्मेदारी है, फ़ंक्शन को आउट पैरामीटर को असाइन करना है। इसे बिना बताए छोड़ने की अनुमति नहीं है।


5

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

निम्न उदाहरण यह दिखाता है:

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

रेफरी: एक संदर्भ पैरामीटर एक चर की स्मृति स्थान के लिए एक संदर्भ है। जब आप संदर्भ द्वारा पैरामीटर पास करते हैं, तो मूल्य मापदंडों के विपरीत, इन मापदंडों के लिए एक नया भंडारण स्थान नहीं बनाया जाता है। संदर्भ पैरामीटर वास्तविक मेमोरी के समान मेमोरी स्थान का प्रतिनिधित्व करते हैं जो विधि को आपूर्ति की जाती है।

C # में, आप रेफरी कीवर्ड का उपयोग करके संदर्भ पैरामीटर घोषित करते हैं। निम्न उदाहरण यह प्रदर्शित करता है:

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}

4

रेफरी और आउट काम सिर्फ संदर्भों से गुजरने और सी ++ के रूप में पॉइंटर्स से गुजरने जैसे हैं।

रेफ के लिए, तर्क को घोषित और आरंभीकृत किया जाना चाहिए।

बाहर के लिए, तर्क को घोषित किया जाना चाहिए, लेकिन प्रारंभिक हो सकता है या नहीं

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);

1
आप एक चर इनलाइन घोषित कर सकते हैं out double Half_nbr:।
सेबस्टियन हॉफमैन

4

संलेखन समय:

(1) हम कॉलिंग विधि बनाते हैं Main()

(2) यह एक सूची वस्तु (जो एक संदर्भ प्रकार की वस्तु है) बनाता है और इसे चर में संग्रहीत करता है myList

public sealed class Program 
{
    public static Main() 
    {
        List<int> myList = new List<int>();

रनटाइम के दौरान:

(3) रनटाइम # 00 पर स्टैक पर मेमोरी आवंटित करता है, एक पते को स्टोर करने के लिए पर्याप्त चौड़ा (# 00 =) myList, क्योंकि चर नाम वास्तव में मेमोरी स्थानों के लिए केवल उपनाम हैं)

(4) रनटाइम स्मृति स्थान पर ढेर पर एक सूची ऑब्जेक्ट बनाता है # एफएफ (ये सभी पते उदाहरण के लिए हैं)

(5) रनटाइम तब # 00 पर वस्तु के शुरुआती पते को # स्टोर करेगा (या शब्दों में, सूचक में सूची ऑब्जेक्ट के संदर्भ को संग्रहीत करता है myList)

संलेखन समय पर वापस:

(६) हम सूची myParamListविधि को तर्क विधि के रूप में पास करते हैं modifyMyListऔर इसे एक नई सूची वस्तु प्रदान करते हैं

List<int> myList = new List<int>();

List<int> newList = ModifyMyList(myList)

public List<int> ModifyMyList(List<int> myParamList){
     myParamList = new List<int>();
     return myParamList;
}

रनटाइम के दौरान:

(7) रनटाइम कॉल विधि के लिए कॉल रूटीन शुरू करता है और इसके हिस्से के रूप में, मापदंडों के प्रकार की जांच करता है।

(8) संदर्भ प्रकार खोजने पर, यह पैरामीटर चर को अलियास करने के लिए # 04 पर स्टैक पर एक मेमोरी आवंटित करता है myParamList

(9) इसके बाद इसमें #FF मान भी जमा हो जाता है।

(10) रनटाइम स्मृति स्थान # 004 पर हीप पर एक सूची ऑब्जेक्ट बनाता है और इस मान के साथ # 04 में #FF बदलता है (या मूल सूची ऑब्जेक्ट को संदर्भित करता है और इस पद्धति में नई सूची ऑब्जेक्ट को इंगित करता है)

# 00 में पता परिवर्तित नहीं किया गया है और #FF के संदर्भ को बरकरार रखता है (या मूल myListसूचक परेशान नहीं है)।


रेफरी कीवर्ड (8) और (9) विधि पैरामीटर के लिए कोई ढेर आवंटन किया जाएगा जिसका मतलब है के लिए क्रम कोड की पीढ़ी को छोड़ने के लिए एक संकलक निर्देश है। यह #FF पर ऑब्जेक्ट को संचालित करने के लिए मूल # 00 पॉइंटर का उपयोग करेगा। यदि मूल पॉइंटर को प्रारंभ नहीं किया जाता है, तो रनटाइम शिकायत को रोक देगा क्योंकि यह वैरिएबल प्रारंभ नहीं होने के बाद आगे नहीं बढ़ सकता है

बाहर कीवर्ड एक संकलक निर्देश जो काफी (9) और (10) पर एक मामूली संशोधन के साथ रेफरी के रूप में ही है। कंपाइलर तर्क की उम्मीद करता है कि यह तर्कहीन है और यह (8), (4) और (5) के साथ हीप पर ऑब्जेक्ट बनाएगा और लॉजिक वेरिएबल में इसके शुरुआती पते को स्टोर करेगा। कोई भी असंवैधानिक त्रुटि नहीं डाली जाएगी और संग्रहीत कोई भी पिछला संदर्भ खो जाएगा।


3

साथ ही आपको किसी अन्य के चर को कक्षा के भिन्न उदाहरण में पुन: असाइन करने की अनुमति देता है, कई मानों आदि को लौटाता है, किसी अन्य व्यक्ति को यह जानने या उपयोग करने देता है कि आपको उनसे क्या आवश्यकता है और आप उनके द्वारा प्रदान किए गए चर के साथ क्या करना चाहते हैं।refout

  • आप की जरूरत नहीं है ref या outतुम सब के लिए जा रहे संशोधित बातें है अगर अंदरMyClass उदाहरण है कि तर्क में पारित हो जाता है someClass

    • कॉलिंग विधि में परिवर्तन दिखाई देंगे जैसे someClass.Message = "Hello World"आप उपयोग करते हैं ref, outया कुछ भी नहीं
    • someClass = new MyClass()अंदर लिखने से केवल विधि के दायरे में myFunction(someClass)देखी गई वस्तु को बाहर निकाल दिया जाता है । कॉल करने की विधि अभी भी मूल उदाहरण के बारे में जानती है जो इसे बनाया गया है और आपकी विधि में पारित हुआ हैsomeClassmyFunctionMyClass
  • आपको जरूरत है ref या outयदि आप someClassएक पूरी नई वस्तु के लिए स्वैपिंग की योजना बनाते हैं और अपने बदलाव को देखने के लिए कॉलिंग विधि चाहते हैं

    • someClass = new MyClass()अंदर लिखने myFunction(out someClass)से उस विधि द्वारा देखी गई वस्तु बदल जाती है जिसे कहा जाता हैmyFunction

अन्य प्रोग्रामर मौजूद हैं

और वे जानना चाहते हैं कि आप उनके डेटा के साथ क्या करने जा रहे हैं। कल्पना कीजिए कि आप एक पुस्तकालय लिख रहे हैं जो लाखों डेवलपर्स द्वारा उपयोग किया जाएगा। आप उन्हें जानना चाहते हैं कि जब वे आपके तरीकों को कहते हैं तो आप उनके चर के साथ क्या करने जा रहे हैं

  • उपयोग करने का refएक बयान है "जब आप मेरी विधि को कॉल करते हैं तो कुछ मान को दिए गए एक चर को पास करें। ध्यान रखें कि मैं इसे अपने तरीके के दौरान पूरी तरह से किसी और चीज़ के लिए बदल सकता हूं। अपने चर को पुरानी वस्तु की ओर इशारा करने की उम्मीद न करें। जब मैं पुर्ण करूॅगा"

  • का उपयोग कर के outएक बयान "मेरी जगह के लिए एक प्लेसहोल्डर चर पास करें। यह कोई फर्क नहीं पड़ता कि यह एक मूल्य है या नहीं; संकलक मुझे एक नए मूल्य पर असाइन करने के लिए मजबूर करेगा। मैं पूरी तरह से गारंटी देता हूं कि आपके द्वारा इंगित की गई वस्तु। इससे पहले कि आप मेरी विधि को कहते हैं, चर, मेरे द्वारा किए जाने वाले समय से अलग होगा

वैसे, C # 7.2 में एक inसंशोधक भी है

और यह विधि को अलग उदाहरण के लिए पारित उदाहरण को स्वैप करने से रोकता है। उन लाखों डेवलपर्स से यह कहने की तरह सोचें "मुझे आपका मूल चर संदर्भ पास करें, और मैं वादा करता हूं कि आपके ध्यान से तैयार किए गए डेटा को किसी और चीज़ के लिए स्वैप न करें"। inकुछ ख़ासियतें हैं, और कुछ मामलों में जहां एक in intसंकलक के साथ एक संक्षिप्त रूपांतरण करने के लिए आपके संक्षिप्त संगत की आवश्यकता हो सकती है , अस्थायी रूप से एक इंट बना देगा, अपने शॉर्ट को इसे चौड़ा करें, इसे संदर्भ द्वारा पास करें और समाप्त करें। यह ऐसा कर सकते हैं क्योंकि आपने घोषित किया है कि आप इसके साथ गड़बड़ नहीं करेंगे।


Microsoft ने .TryParseसंख्यात्मक प्रकारों पर विधियों के साथ ऐसा किया :

int i = 98234957;
bool success = int.TryParse("123", out i);

पैरामीटर को चिह्नित करने के रूप में outवे सक्रिय रूप से यहां घोषणा कर रहे हैं "हम निश्चित रूप से 98234957 के अपने श्रमसाध्य रूप से तैयार किए गए मूल्य को कुछ और के लिए बदलने जा रहे हैं "

बेशक, वे थोड़े मूल्य के प्रकारों की तरह चीजों के लिए है, क्योंकि अगर पार्स विधि कुछ और के लिए मूल्य प्रकार स्वैप करने की अनुमति नहीं थी यह बहुत अच्छी तरह से काम नहीं करेगा .. लेकिन कल्पना कीजिए कि कुछ में कुछ काल्पनिक विधि थी लाइब्रेरी आप बना रहे हैं:

public void PoorlyNamedMethod(out SomeClass x)

आप देख सकते हैं कि यह एक है out, और आप इस प्रकार जान सकते हैं कि यदि आप घंटों क्रंचिंग नंबर बिताते हैं, तो कुछ परफेक्ट बनाते हैं:

SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);

खैर यह समय की बर्बादी थी, उस संपूर्ण वर्ग को बनाने में उन सभी घंटों का समय लगा। यह निश्चित रूप से दूर फेंक दिया जा रहा है और PoorlyNamedMethod द्वारा प्रतिस्थापित किया जा रहा है


3

संक्षिप्त जवाब देखने वालों के लिए।

दोनों refऔर outकीवर्ड का उपयोग पास-पास करने के लिए किया जाता है reference


refकीवर्ड के एक वैरिएबल का मान होना चाहिए या किसी ऑब्जेक्ट का संदर्भ होना चाहिए या इसके गुजरने null से पहले होना चाहिए ।


विपरीत ref, के एक चर outकीवर्ड एक मान होना चाहिए या किसी वस्तु के लिए या संदर्भ देना चाहिए null के बाद अपनी गुजर एक मूल्य है या किसी वस्तु का उल्लेख करने की कोई जरूरत है और साथ ही पहले से गुजर रहा।


2

कई उत्कृष्ट व्याख्याओं को स्पष्ट करने के लिए, मैंने निम्नलिखित कंसोल ऐप विकसित किया:

using System;
using System.Collections.Generic;

namespace CSharpDemos
{
  class Program
  {
    static void Main(string[] args)
    {
      List<string> StringList = new List<string> { "Hello" };
      List<string> StringListRef = new List<string> { "Hallo" };

      AppendWorld(StringList);
      Console.WriteLine(StringList[0] + StringList[1]);

      HalloWelt(ref StringListRef);
      Console.WriteLine(StringListRef[0] + StringListRef[1]);

      CiaoMondo(out List<string> StringListOut);
      Console.WriteLine(StringListOut[0] + StringListOut[1]);
    }

    static void AppendWorld(List<string> LiStri)
    {
      LiStri.Add(" World!");
      LiStri = new List<string> { "¡Hola", " Mundo!" };
      Console.WriteLine(LiStri[0] + LiStri[1]);
    }

    static void HalloWelt(ref List<string> LiStriRef)
     { LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }

    static void CiaoMondo(out List<string> LiStriOut)
     { LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
   }
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/
  • AppendWorld: StringListनाम की एक प्रति LiStriपारित की जाती है। विधि की शुरुआत में, यह प्रतिलिपि मूल सूची को संदर्भित करती है और इसलिए इसका उपयोग इस सूची को संशोधित करने के लिए किया जा सकता है। बाद में विधि के अंदर LiStriएक अन्य List<string>ऑब्जेक्ट का संदर्भ देता है जो मूल सूची को प्रभावित नहीं करता है।

  • HalloWelt: LiStriRefपहले से ही प्रारंभिक का एक उपनाम है ListStringRef। पारित List<string>वस्तु का उपयोग किसी नए को शुरू करने के लिए किया जाता है, इसलिए refआवश्यक था।

  • CiaoMondo: LiStriOutका एक अन्य नाम है ListStringOutऔर इसे आरंभीकृत किया जाना चाहिए।

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


1

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

int x;    Foo(out x); // OK 
int y;    Foo(ref y); // Error

रेफ पैरामीटर डेटा के लिए हैं जिन्हें संशोधित किया जा सकता है, पैरामीटर उन डेटा के लिए हैं जो फ़ंक्शन के लिए एक अतिरिक्त आउटपुट है (जैसे int.TryParse) जो पहले से ही कुछ के लिए रिटर्न मान का उपयोग कर रहे हैं।


1

नीचे मैंने Ref और out दोनों का उपयोग करके एक उदाहरण दिखाया है । अब, आप सभी को रेफ और आउट के बारे में मंजूरी दे दी जाएगी।

नीचे दिए गए उदाहरण में जब मैं टिप्पणी करता हूं // myRefObj = new myClass {Name = "रेफरी बाहर बुलाया" "}; पंक्ति, " त्रुटि रहित स्थानीय चर 'myRefObj' का उपयोग करते हुए एक त्रुटि प्राप्त करेगी , लेकिन इसमें कोई त्रुटि नहीं है

Ref का उपयोग कहां करें : जब हम किसी पैरामीटर के साथ एक प्रक्रिया को बुला रहे हैं और उसी पैरामीटर का उपयोग उस खरीद के आउटपुट को संग्रहीत करने के लिए किया जाएगा।

कहां से उपयोग करें: जब हम किसी पैरामीटर के साथ एक प्रक्रिया को बुला रहे हैं और उस खरीद से मूल्य वापस करने के लिए एक ही परम का उपयोग किया जाएगा। उत्पादन पर भी ध्यान दें

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 

1
 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

आप इस कोड की जांच कर सकते हैं यह आपको इसका पूरा अंतर बताएगा जब आप "रेफ" का उपयोग करते हैं तो इसका मतलब यह है कि यू पहले से ही उस int / string को इनिशियलाइज़ करता है।

लेकिन जब आप "आउट" का उपयोग करते हैं, तो यह दोनों स्थितियों में काम करता है, आप उस int / string को इनिशियलाइज़ करते हैं या नहीं, लेकिन u को उस फंक्शन में उस int / string को इनिशियलाइज़ करना चाहिए


1

Ref: संदर्भ के रूप में एक तर्क पारित करने के लिए रेफ कीवर्ड का उपयोग किया जाता है। इसका मतलब यह है कि जब उस पैरामीटर का मान विधि में बदला जाता है, तो यह कॉलिंग विधि में परिलक्षित होता है। एक तर्क जिसे रेफरी कीवर्ड का उपयोग करके पारित किया जाता है, उसे कॉलिंग विधि में आरंभीकृत किया जाना चाहिए इससे पहले कि उसे कॉल किया जाए।

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

public class Example
{
 public static void Main() 
 {
 int val1 = 0; //must be initialized 
 int val2; //optional

 Example1(ref val1);
 Console.WriteLine(val1); 

 Example2(out val2);
 Console.WriteLine(val2); 
 }

 static void Example1(ref int value) 
 {
 value = 1;
 }
 static void Example2(out int value) 
 {
 value = 2; 
 }
}

/* Output     1     2     

रेफरी और विधि ओवरलोडिंग में

रेफरी और आउट दोनों को एक साथ ओवरलोडिंग की विधि में उपयोग नहीं किया जा सकता है। हालाँकि, रेफ और आउट का इलाज अलग-अलग समय पर किया जाता है, लेकिन उनका संकलन समय पर ही किया जाता है (CLR दोनों के बीच अंतर नहीं करता है जबकि इसे Ref और out के लिए IL बनाया गया है)।


0

एक विधि के दृष्टिकोण से, जो एक पैरामीटर प्राप्त करता है, के बीच का अंतर है refऔर outयह है कि C # की आवश्यकता है कि तरीकों को outलौटने से पहले हर पैरामीटर को लिखना चाहिए , और इस तरह के एक पैरामीटर के साथ कुछ भी नहीं करना चाहिए, इसे outपैरामीटर के रूप में पारित करने या इसे लिखने के अलावा। , जब तक कि इसे या तो किसी outअन्य विधि के पैरामीटर के रूप में पारित नहीं किया गया है या सीधे लिखा गया है। ध्यान दें कि कुछ अन्य भाषाओं में ऐसी आवश्यकताएं नहीं हैं; एक वर्चुअल या इंटरफ़ेस विधि जिसे एक outपैरामीटर के साथ C # में घोषित किया जाता है, उसे किसी अन्य भाषा में ओवरराइड किया जा सकता है, जो ऐसे मापदंडों के लिए कोई विशेष प्रतिबंध नहीं लगाता है।

फोन करने वाले के दृष्टिकोण से, सी # कई परिस्थितियों में मान लेंगे जब एक outपैरामीटर के साथ एक विधि को कॉल करने से पारित चर को पहले पढ़े बिना लिखा जा सकेगा। अन्य भाषाओं में लिखी गई विधियों को कॉल करते समय यह धारणा सही नहीं हो सकती है। उदाहरण के लिए:

struct MyStruct
{
   ...
   myStruct(IDictionary<int, MyStruct> d)
   {
     d.TryGetValue(23, out this);
   }
}

यदि असाइनमेंट की तरह लगने वाले C # के अलावा किसी अन्य भाषा में लिखे गए कार्यान्वयन की myDictionaryपहचान करता है , तो यह संभवतः अनमॉडिफाइड छोड़ सकता है ।IDictionary<TKey,TValue>MyStruct s = new MyStruct(myDictionary);s

ध्यान दें कि VB.NET में लिखे गए कंस्ट्रक्टर, C # के उन लोगों के विपरीत, इस बारे में कोई धारणा नहीं बनाते हैं कि क्या विधियाँ किसी outपैरामीटर को संशोधित करेंगी , और बिना शर्त सभी क्षेत्रों को खाली कर देंगी । ऊपर दिया गया विषम व्यवहार पूरी तरह से VB में या पूरी तरह से C # में लिखे गए कोड के साथ नहीं होगा, लेकिन C # में लिखे कोड को VB.NET में लिखे गए तरीके से कॉल करने पर हो सकता है।


0

यदि आप अपने पैरामीटर को रेफरी के रूप में पास करना चाहते हैं तो आपको फंक्शन पैरामीटर को पास करने से पहले इसे इनिशियलाइज़ करना चाहिए अन्यथा कंपाइलर खुद ही एरर दिखाएगा। लेकिन ऑउट पैरामीटर के मामले में आपको ऑब्जेक्ट पैरामीटर को पास करने से पहले इसे शुरू करने की आवश्यकता नहीं है। method.You कॉलिंग विधि में ऑब्जेक्ट को इनिशियलाइज़ कर सकते हैं।


-3

अच्छी तरह से समझें कि फ़ंक्शन के अंदर जो संदर्भ पैरामीटर पास किया गया है, उस पर सीधे काम किया जाता है।

उदाहरण के लिए,

    public class MyClass
    {
        public string Name { get; set; }
    }

    public void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog".
    }

    public void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

यह डॉग लिखेगा, कैट नहीं। इसलिए आपको someObject पर सीधे काम करना चाहिए।


6
जबकि यहाँ सब कुछ बहुत अधिक सच है, यह वास्तव में संदर्भ द्वारा या बाहर मूल्य के बीच के अंतर को स्पष्ट नहीं करता है। सबसे अच्छा यह आधा संदर्भ और मूल्य / अपरिवर्तनीय प्रकारों के बीच का अंतर बताता है।
कोनराड फ्रैक्स

यदि आप चाहते हैं कि बिल्ली लिखने के लिए कोड कृपया उस ऑब्जेक्ट को 'रेफ' कुंजी के साथ पास करें: सार्वजनिक स्थैतिक शून्य बार (रेफरी MyClass someObject), बार (रेफरी myObject);
डैनियल बोटेरो कोरे

-4

मैं इस पर इतना अच्छा नहीं हो सकता, लेकिन निश्चित रूप से तार (भले ही वे तकनीकी रूप से संदर्भ प्रकार हैं और ढेर पर रहते हैं) मूल्य द्वारा पारित किए जाते हैं, संदर्भ नहीं?

        string a = "Hello";

        string b = "goodbye";

        b = a; //attempt to make b point to a, won't work.

        a = "testing";

        Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

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

जहाँ तक मैं जानता हूँ कि आपको केवल संरचना / मूल्य प्रकार और स्ट्रिंग के लिए रेफरी की आवश्यकता है, क्योंकि स्ट्रिंग एक संदर्भ प्रकार है जो इसे दिखावा करता है, लेकिन एक मूल्य प्रकार नहीं है।

मैं यहां पूरी तरह से गलत हो सकता हूं, हालांकि, मैं नया हूं।


5
स्टैक ओवरफ्लो में आपका स्वागत है, एडविन। स्ट्रिंग्स को संदर्भ द्वारा पारित किया जाता है, किसी भी अन्य ऑब्जेक्ट की तरह, जहां तक ​​मुझे पता है। आप भ्रमित हो सकते हैं क्योंकि तार अपरिवर्तनीय वस्तु हैं, इसलिए यह स्पष्ट नहीं है कि वे संदर्भ द्वारा पारित किए गए हैं। कल्पना कीजिए कि स्ट्रिंग में एक विधि होती है Capitalize(), जो स्ट्रिंग की सामग्री को बड़े अक्षरों में बदल देगी। यदि आपने अपनी लाइन a = "testing";को फिर से बदल दिया a.Capitalize();, तो आपका आउटपुट "हेलो" होगा, न कि "हैलो"। अपरिवर्तनीय प्रकारों में से एक लाभ यह है कि आप संदर्भों के आसपास से गुजर सकते हैं और मूल्य को बदलने वाले अन्य कोड के बारे में चिंता नहीं करते हैं।
डॉन किर्कबी

2
तीन मौलिक प्रकार के शब्दार्थ हैं एक प्रकार का खुलासा कर सकते हैं: उत्परिवर्ती संदर्भ शब्दार्थ, उत्परिवर्ती मूल्य शब्दार्थ और अपरिवर्तनीय शब्दार्थ। एक प्रकार T के चर x और y पर विचार करें, जिसमें फ़ील्ड या गुण m है, और मान लें कि x को y पर कॉपी किया गया है। यदि T का संदर्भ शब्दार्थ है, तो ym द्वारा xm में परिवर्तन देखा जाएगा। यदि T का अर्थ शब्दार्थ है, तो कोई भी ym को प्रभावित किए बिना xm को बदल सकता है यदि T में अपरिवर्तनीय शब्दार्थ है, तो न तो xm और न ही ym कभी बदलेंगे। अपरिवर्तनीय शब्दार्थ को संदर्भ या मूल्य वस्तुओं द्वारा अनुकरण किया जा सकता है। स्ट्रिंग्स अपरिवर्तनीय संदर्भ ऑब्जेक्ट हैं।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.