C# Pass by Reference

C# Pass by Reference: जब हम किसी Method यानी Named Code Block को Create करते हैं, तो उसे Use करने के लिए हम हमारे Program में जब उस Method के नाम को Parenthesis का प्रयोग करते हुए Specify करते हैं, तो इस प्रक्रिया को Method Call करना या Method Invoke करना कहा जाता है।

उदाहरण के लिए पिछले Program में हमने निम्न Statement द्वारा addition() Method को Main() Method में Call किया था या दूसरे शब्दों में कहें तो addition() Method को Invoke किया था:

total = myObj.addition(value1, value2);

जब हम Current Method में किसी दूसरे Method को Call करते हैं, तो Program Control Current Program के Execution को Current Point पर छोडकर उस Method में पहुंच जाता है, जिसे Call किया गया है और उस Method के सभी Statements को Execute करने के बाद Program Control फिर से पिछले Method में उसी Location पर पहुंचता है, जहां से Program Control Called Method में Pass हुआ था। इस प्रक्रिया को हम निम्न चित्र द्वारा समझ सकते हैं:

Method Invocation or Method Calling - Hindi

Parameters Passing : By Value and By Reference

किसी Function के Parenthesis के बीच जिन Values को Specify किया जाता है, उन्हें Parameters अथवा Arguments कहते हैं। Method को Call करते समय Specify किए जाने वाले Actual Parameters को Argument के रूप में Method द्वारा Create किए गए Local Variables या Objects में प्राप्त किया जाता है और Method में Specified Code Statements द्वारा Parameters के रूप में आने वाले Value Type या Reference Types के मानों को Required Processing Apply करने के बाद Method के अन्दर ही Result Generate करके या तो आगे की Processing के लिए Calling Method को Return कर दिया जाता है अथवा Currently Called Method में ही Output के रूप में Display कर दिया जाता है। Method में Pass किए जाने वाले Parameters मूलत: Value TypesReference Types के आधार पर दो प्रकार के हो सकते हैं।

जब हम किसी Method को Call करते समय उसमें Value Type Parameters Pass करते हैं, तो वास्तव में Called Method में Calling Method से Pass होने वाले Parameters के Actual मानों का Copy ही Pass होता है। इसलिए यदि हम Called Method में Pass किए गए Parameters के मानों में किसी तरह का कोई परिवर्तन करें, तो उस परिवर्तन का प्रभाव Calling Method के मान पर नहीं पडता।

लेकिन कई बार हमें ऐसी जरूरत पडती है, जहां Parameter के रूप में Pass किए गए Variable के मान को हमें किसी Method द्वारा Change या Modify करना होता है। इस जरूरत को पूरा करने के लिए C# हमें ref नाम का एक Keyword Provide करता है।

यानी यदि हम Parameters Pass करते समय Value Type Variable के साथ ref Keyword को Specify कर दें, तो Pass होने वाला Variable By Reference Pass होता है और यदि इस प्रकार से Pass किए गए किसी Variable के मान को कोई Called Method Change करता है, तो उस Change का Effect, Calling Method के Variable पर भी पडता है। इस पूरी प्रक्रिया को हम निम्न Program द्वारा बेहतर तरीके से समझ सकते हैं:

File Name: MethodParametersFormalValue.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class MethodParametersFormalValue
    {
        private static void Main(string[] args)
        {
            int value = 100;

            Console.WriteLine("Before Method Execution, value={0}", value);

            ChangeParameters(value);

            Console.WriteLine("After Method Execution, value={0}", value);
        }

        static void ChangeParameters(int value)
        {
            value = 200;
        }
    }
}

Output:
	Before Method Execution, value=100
	After Method Execution, value=100

जैसाकि इस Program के Output द्वारा हम समझ सकते हैं कि हालांकि हमने Main() Method से value नाम के Value Type Variable को एक Static Method में Parameter के रूप में Pass किया है और Called Method ने Parameter के रूप में आने वाले value नाम के Value Type Variable के मान को Change भी किया है। लेकिन Called Method के अन्दर किए गए इस Change का प्रभाव Calling Method के Variable के मान पर नहीं पडता।

क्योंकि जब हम Calling Method से किसी Value Type Parameter को किसी Called Method में Pass करते हैं, तो Default रूप से वह Parameter By Value ही Pass होता है और Called Method में Create होने वाले एक नए Variable में Copy की तरह Store होता है। इसी Program में Value को Pass करने के तरीके को हम निम्नानुसार तरीके से Modify भी कर सकते हैं:

File Name: MethodParametersActualValue.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class MethodParametersFormalValue
    {
        private static void Main(string[] args)
        {
            int value = 100;

            Console.WriteLine("Before Method Execution, value={0}", value);

            ChangeParameters(ref value);

            Console.WriteLine("After Method Execution, value={0}", value);
        }

        static void ChangeParameters(ref int value)
        {
            value = 200;
        }
    }
}

Output:
	Before Method Execution, value=100
	After Method Execution, value=200

इस Modified Program में हमने value नाम के Value Type Variable को Calling Method Main() से Called Method ChangeParameters() में Pass करते समय हमने Parameter को भी निम्नानुसार ref Keyword के साथ Specify किया है:

ChangeParameters(ref value);

जबकि Called Method को Define करते समय भी हमने निम्नानुसार ref Keyword का प्रयोग किया है:

static void ChangeParameters(ref int value)

चूंकि, इस बार Main() Method से ChangeParameters() Method में Pass होने वाले Parameters के मान की Copy Pass नहीं होती, बल्कि स्वयं Variable का मान ही Pass हो जाता है। इसलिए जब इस बार ChangeParameters() Method value नाम के Value Type के Variable के मान में परिवर्तन करता है, तो उसका प्रभाव Main() Method यानी Calling Method के Variable के मान पर ही पडता है।

यही वजह है कि ChangeParameters() Method को Call करने के बाद इस प्रकार प्राप्त होने वाला Output पिछले वाले Program की तुलना में अलग है। क्योंकि इस बार हमने Called Method में Calling Method के Actual Parameters को Pass किया है, उनकी Copy को नहीं जबकि पिछले Program में हमने Parameters के मान की केवल एक Copy को Pass किया था।

इसलिए पिछले Program का ChangeParameters() Method केवल Parameter की Copy को Modify कर रहा था, जबकि इस Program का ChangeParameters() Method स्वयं Main() Method के Actual Variable को Change कर रहा है।

जिस तरह से हम किसी Value Type Variable के मान को Formal व Actual Parameter के रूप में Method में Pass कर सकते हैं, उसी तरह से हम किसी Reference Type को भी FormalActual Parameter की तरह Method में Pass कर सकते हैं और Method इन Reference Types को भी वैसे ही Treat करता है, जैसे Value Type को Treat करता है।

यानी जब हम Reference Type को किसी Called Method में By Value Pass करते हैं, तो Called Method एक नया Object Create करता है और उस Object में Parameter के रूप में आने वाले Object के सभी Data Members की Copy कर देता है।

इसलिए यदि इस Copy Object के किसी Data Member के मान में ये Method किसी तरह का कोई परिवर्तन करता है, तो उस परिवर्तन का प्रभाव Calling Method के Object के Data Members पर नहीं पडता।

लेकिन यदि Calling Method से Called Method में Parameter के रूप में किसी Object को Pass करते समय ref Keyword का प्रयोग किया जाए, तो Value Type की तरह ही Reference Type भी Calling Method के Actual Object को ही Refer करता है।

इस स्थिति में यदि Called Method, Calling Method से आने वाले Parameters के Data Members के मान में किसी तरह का कोई परिवर्तन करता है, तो उसका प्रभाव Calling Method के Object में भी Reflect होता है

लेकिन क्योंकि जब हम किसी Reference Type के Object को Formal Parameter के रूप में किसी Called Method में Pass करते हैं, तब भी हम Object के Heap Area में Stored Data Part के Reference को ही Pass कर रहे होते हैं। इसलिए यदि हम Method के अन्दर भी Object के Data Members के मान में परिवर्तन करें, तो Actual Object के Heap Area में Stored मानों में ही परिवर्तन होता है।

लेकिन Called Method में Create होने वाले Object को यदि नया Object Create करके उसका Reference Specify कर दें, तो उस स्थिति में Called Method जिस Heap Area Object को Reference करेगा, वह Object और Called Method जिस Heap Area Object को Refer कर रहा है, वह Object यानी दोनों Objects अलग-अलग Heap Area को Refer करेंगे। जैसे:

// File Name: MethodParametersFormalReference.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class MyClass { public int Value = 20; }

    class MethodParametersFormalReference
    {
        static void RefAsParameter(MyClass objByVal)
        {
            objByVal.Value = 50;
            Console.WriteLine("After member assignment: {0}", objByVal.Value);

            objByVal = new MyClass();
            Console.WriteLine("After new object creation: {0}", objByVal.Value);
        }

        static void Main()
        {
            MyClass obj = new MyClass();
            Console.WriteLine("Before method call: {0}", obj.Value);
            RefAsParameter(obj);
            Console.WriteLine("After method call: {0}", obj.Value);
        }
    }
}

// Output:
   Before method call: 20
   After member assignment: 50
   After new object creation: 20
   After method call: 50

इस Program में सबसे पहले हमने MyClass नाम की एक नया Type Create किया है, जिसमें value नाम के एक Public Field को Define किया है, ताकि कोई भी Class इसे Directly Access कर सके।

जब Program सबसे पहले Main() Method में पहुंचता है, तो निम्नानुसार Statement द्वारा obj नाम का MyClass Type का एक Object Create करता है:

MyClass obj = new MyClass();

और इस Newly Created Object के value Property के मान को Output में निम्नानुसार Statement द्वारा Display करता है:

Console.WriteLine(“Before method call: {0}”, obj.Value);

परिणामस्वरूप हमें निम्न Output प्राप्त होता है:

Before method call: 20

फिर निम्न Statement द्वारा RefAsParameter() Method को Call किया जाता है और इस Method में Parameter के रूप में Newly Created MyClass Type के Object obj को By Value Pass किया जाता है:

RefAsParameter(obj);

By Value आने वाले MyClass Type के Object obj के मान को Accept करने के लिए RefAsParameter() Method में निम्नानुसार MyClass Type का objByVal नाम का एक Object Create किया जाता है:

static void RefAsParameter(MyClass objByVal)

चूंकि C# में सभी Reference Types दो Segments में Memory में Store होते हैं, जहां Actual Data तो Memory के Heap Area में Store होता है जबकि उस Heap Area का Address एक Reference के रूप में Stack में Store होता है।

इसलिए जब Main() Method से obj को Parameter की तरह RefAsParameter() Method में Pass किया जाता है, तो इस Method में Create होने वाले objByVal में भी केवल Memory में Stored Actual Data का Reference ही Store होता है। यानी निम्न चित्रानुसार objobjByVal, दोनों ही Memory के समान Heap Area को Reference करने लगते हैं:

C# Pass by Reference - Hindi

इसलिए जब RefAsParameter() Method का निम्न Statement Execute होता है:

objByVal.Value = 50;

तो वह Heap Area में Stored Data के मान को Change करके निम्न चित्रानुसार 50 पर देता है:

C# Pass by Reference - Hindi

जैसाकि इस चित्र द्वारा हम समझ सकते हैं कि हालांकि Heap Area के Data को Method के Local Object objByVal ने Change करके 50 किया है, लेकिन यही मान Main() Method के obj Object के लिए भी Modified हो गया है, क्योंकि दोनों ही Objects समान Heap Area Data को Refer कर रहे थे, इसलिए दोनों में से कोई भी यदि इस Data को Change करेगा, तो दूसरे को Modified Data ही प्राप्त होगा। इसीलिए जब डमजीवक का निम्न Statement Execute होता है:

Console.WriteLine(“After member assignment: {0}”, objByVal.Value);

तो हमें Output में निम्नानुसार परिणाम प्राप्त होता है:

After member assignment: 50

लेकिन जब Called Method का निम्न Statement Execute होता है:

objByVal = new MyClass();

तो C# Compiler एक नया MyClass Type Object Create करने के लिए Heap Area में Memory Reserve करता है और इस Newly Reserved Memory का Reference objByVal को Assign कर देता है। परिणामस्वरूप अब objobjByVal दोनों MyClass Type Objects निम्न चित्रानुसार दो अलग Heap Area Memory को Refer करने लगते हैं:

C# Pass by Reference - Hindi

इसलिए अब जब Called Method का निम्न Statement Execute होता है:

Console.WriteLine(“After new object creation: {0}”, objByVal.Value);

तो अब objByVal Object एक Newly Created MyClass Type Object को Refer करता है, जिसके Create होते ही उसके value नाम के Field का Default मान 20 Set हो जाता है। इसलिए इस बार objByVal.Value Statement ही Output के रूप में निम्नानुसार एक नया मान Display करता है:

After new object creation: 20

जबकि इसी Method में पिछली बार जब इसी Statement को Execute किया गया था, तो निम्नानुसार Output प्राप्त हो रहा था, जिसमें Field का मान 50 था। क्योंकि उस समय objByVal Object Called Method के obj Object के Heap Area को Refer कर रहा था।

जब Program Control इस Statement को Execute करके फिर से Main() Method में Retune होता है, तो निम्नानुसार Statement Execute होता है:

Console.WriteLine(“After method call: {0}”, obj.Value);

और इस Statement के Execute होने पर हमें निम्नानुसार Output प्राप्त होता है:

After method call: 50

हम देख सकते हैं कि Method Call होने से पहले हमें इसी Statement को Run करने पर हमें निम्नानुसार Output प्राप्त हो रहा था जिसमें value Field का मान 20 था:

Before method call: 20

हालांकि हमने obj को Method में By Value Pass किया था, लेकिन By Value Pass करने पर भी Calling Method से किसी Object का Reference ही Pass होता है। इसीलिए यदि Called Method, Calling Method से By Value आने वाले Object के Field या Data Member के मान में भी परिवर्तन करता है, तो वह परिवर्तन Calling Method के Object में ही होता है, क्योंकि objobjByVal दोनों ही समान Heap Area को Reference कर रहे होते हैं।

लेकिन जब एक बार Calling Method से Pass किए गए obj को Called Method में Accept करने के बाद Called Method में इस objByVal Reference को ही Change कर दिया जाता है, यानी Called Method में objByVal किसी अन्‍य Memory Area या Object को Refer करने लगता है, तब भी Main() Method का obj उसी Heap Area को Refer करता है, जिसे पहले कर रहा था। क्योंकि objByValobj दो अलग Objects हैं, जो समान या अलग-अलग Heap Area Memory को Reference कर सकते हैं।

लेकिन यदि हम हमारे पिछले Program को निम्नानुसार Modify करते हुए Parameter के रूप में Pass होने वाले Object के Reference को By Reference Specify कर दें, तो यदि Called Method में Parameter के रूप में Specified Object किसी दूसरे Memory Heap Area को Refer करने लगे, तो Calling Method में भी Parameter के रूप में Pass किया गया Reference Object उसी Memory Heap Area को Refer करने लगेगा।

// File Name: MethodParametersActualReference.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class MyClass { public int Value = 20; }

    class MethodParametersActualReference
    {
        static void RefAsParameter(ref MyClass objByRef)
        {
            objByRef.Value = 50;
            Console.WriteLine("After member assignment: {0}", objByRef.Value);

            objByRef = new MyClass();
            Console.WriteLine("After new object creation: {0}", objByRef.Value);
        }
        static void Main()
        {
            MyClass obj = new MyClass();
            Console.WriteLine("Before method call: {0}", obj.Value);
            RefAsParameter(ref obj);
            Console.WriteLine("After method call: {0}", obj.Value);
        }
    }
}

// Output:
   Before method call: 20
   After member assignment: 50
   After new object creation: 20
   After method call: 20

इस बार भी ये Program Execute होते ही MyClass Type का obj नाम का एक Object Create करता है और उसके value नाम के Field को निम्न Statement द्वारा Output में Display करता है:

Before method call: 20

फिर RefAsParameter() Method Call किया जाता है और obj Object को Parameter की तरह Pass किया जाता है। लेकिन इस बार इस Object को ref Keyword का प्रयोग करते हुए By Reference Pass किया जाता है।

इसलिए इस बार objobjByRef नाम के दो अलग Reference Variables Create नहीं होते बल्कि एक ही Reference के दो नाम Create हो जाते हैं, जिसे हम निम्न चित्रानुसार ज्यादा बेहतर तरीके से समझ सकते हैं:

C# Pass by Reference - Hindi

इसलिए जब निम्न Statement Execute होता है:

objByRef.Value = 50;

तो objByRef नाम का MyClass Type का एक नया Object Create नहीं होताए जो कि Parameter के रूप में आने वाले Reference Type के Reference को Hold करे, बल्कि स्वयं उस Heap Area Memory को Refer करने लगता है, जिसे obj Refer कर रहा है।

इसलिए जब उपरोक्त Code Execute होता है, तो उसी Heap Area के value Field का मान Change हो जाता है, जिसे obj Refer कर रहा होता है। फिर जब निम्न Statement Execute होता है:

objByRef = new MyClass();

तो objByRef एक नए Heap Area Memory को Refer करने लगता है और चूंकि objByRefobj दोनों दो नहीं बल्कि एक ही Memory Area के दो नाम हैं, इसलिए objByRef को एक नए MyClass Object का Reference Assign करने से Main() Method में Exist obj Object भी एक नए MyClass Type Object को Refer करने लगता है, जिसके value Field या Data Member का Default मान 20 होता है।

इसलिए जब Program Control इस Method से Return होकर फिर से Main() Method में पहुंचता है, तो अब Main() Method में obj Object उसी Heap Area को Refer नहीं कर रहा होताए जिसे RefAsParameter() Method को Call करने से पहले कर रहा था, बल्कि एक नए MyClass Type के एक नए Object को Refer कर रहा होता है, जिसे हम निम्न चित्रानुसार ज्यादा बेहतर तरीके से समझ सकते हैं:

C# Pass by Reference - Hindi

इसलिए RefAsParameter() Method को Call करने से पहले व RefAsParameter() Method का Call करने के बाद दोनों ही समय इनके value नाम के Data Member का मान 20 ही रहता है, लेकिन दोनों ही समय पर obj Object अलग Heap Area को Refer कर रहा होता है।

Output Parameters

Output Parameters ऐसे Parameters होते हैं, जिन्हें out Keyword का प्रयोग करके उपयोग में लिया जाता है। ये Parameters Exactly Reference Type Parameter की तरह ही काम करते हैं।

// File Name: MethodOutParameters.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class MyClass { public int Value = 20; }

    class MethodParametersActualReference
    {
        static void RefAsParameter(out MyClass objByRef)
        {
            objByRef.Value = 50;
            Console.WriteLine("After member assignment: {0}", objByRef.Value);

            objByRef = new MyClass();
            Console.WriteLine("After new object creation: {0}", objByRef.Value);
        }
        static void Main()
        {
            MyClass obj = new MyClass();
            Console.WriteLine("Before method call: {0}", obj.Value);
            RefAsParameter(out obj);
            Console.WriteLine("After method call: {0}", obj.Value);
        }
    }
}

// Output:
   Before method call: 20
   After member assignment: 50
   After new object creation: 20
   After method call: 20

ये Program Exactly पिछले वाले Program की तरह ही काम करता है और Exactly समान Output देता है।

जब हम out Parameter का प्रयोग करके किसी Called Method में Value Type या Reference Type Parameters Pass करते हैं, तो वास्तव में हम समान Memory Area को Refer करने वाला एक Alias Create कर लेते हैं। यानी यदि पिछले Program के आधार पर समझें, तो objByRef वास्तव में obj का ही दूसरा नाम है और दोनों समान Memory Location को ही Refer कर रहे हैं।

जब हम out Parameter को Use करते हैं, तब ये जरूरी होता है कि Called Method out Parameter को कोई न कोई मान जरूर Assign करे। साथ ही जब हम out Parameter Use करते हैं, तब Method से कोई मान Return न करवाने पर भी out Parameter में Assign किया गया मान Called Method में Use करने के लिए Available हो जाता है। जैसे:

// File Name: OutParameters.cs
using System;

namespace CSharpIntermediateConstructsMethod
{
    class OutParameters
    {
        private static void Main(string[] args)
        {
            int outParamter;
            Addition(10, 20, out outParamter);
            Console.WriteLine("Addition of 10+20 = {0}", outParamter);
        }

        static void Addition(int x, int y, out int value)
        {
            value = x + y;
        }
    }
}

// Output:
	Addition of 10+20 = 30

इस Program में हमने outParamter नाम का एक Output Parameter Specify किया है और Called Method में हमने इसे x + y के मान से Assign किया है, जिन्हे पहले दो Arguments के रूप में Main() Method से Pass किया गया है। परिणामस्वरूप Calling Method में outParamter उस मान से Set हो जाता है, जिसे Addition() नाम के Method में x + y के मान से Set किया है।

इसलिए हालांकि Called Method कोई भी मान Return नहीं कर रहा है, फिर भी Calling Method में Called Method द्वारा outParamter के रूप में x + y का मान प्राप्त हो रहा है, जिसे Calling Method में निम्नानुसार Statement द्वारा Display किया गया है:

Console.WriteLine(“Addition of 10+20 = {0}”, outParamter);

और Output के रूप में ये Statement हमें निम्नानुसार Result Provide करता है:

Addition of 10+20 = 30

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS