VBA
बीइंग रीफ या बायवैल का तर्क
खोज…
परिचय
ByRef
और ByVal
संशोधक एक प्रक्रिया के हस्ताक्षर का हिस्सा हैं और इंगित करते हैं कि कैसे एक तर्क एक प्रक्रिया को पारित किया जाता है। VBA में एक पैरामीटर ByRef
पारित किया जाता है जब तक कि अन्यथा निर्दिष्ट नहीं किया जाता है (अर्थात अनुपस्थित होने पर ByRef
निहित है)।
नोट : कई अन्य प्रोग्रामिंग भाषाओं में (VB.NET सहित), यदि कोई संशोधक निर्दिष्ट नहीं किया गया है, तो पैरामीटर को मूल रूप से मान से पास किया जाता है: संभावित भ्रम से बचने के लिए ByRef
संशोधक को स्पष्ट रूप से निर्दिष्ट करने पर विचार करें।
टिप्पणियों
पासिंग ऐरे
एरे को संदर्भ द्वारा पारित किया जाना चाहिए। यह कोड संकलित करता है, लेकिन रन-टाइम त्रुटि 424 "ऑब्जेक्ट आवश्यक" उठाता है:
Public Sub Test()
DoSomething Array(1, 2, 3)
End Sub
Private Sub DoSomething(ByVal foo As Variant)
foo.Add 42
End Sub
यह कोड संकलित नहीं करता है:
Private Sub DoSomething(ByVal foo() As Variant) 'ByVal is illegal for arrays
foo.Add 42
End Sub
पासिंग सिंपल वेरिएबल्स बायफ एंड बाइवाल
ByRef
या ByVal
इंगित करता है कि क्या CalledProcedure
द्वारा CalledProcedure
को एक तर्क का वास्तविक मान दिया गया है, या CallingProcedure
एक संदर्भ (जिसे कुछ अन्य भाषाओं में पॉइंटर कहा जाता है) पास किया गया है CalledProcedure
।
यदि किसी तर्क को ByRef
पास किया जाता है, तो तर्क का मेमोरी पता CalledProcedure
को पास कर दिया जाता है और CalledProcedure
द्वारा उस पैरामीटर के किसी भी संशोधन को CalledProcedure
में मान कर दिया CallingProcedure
।
एक तर्क पारित हो जाता है तो ByVal
, वास्तविक मूल्य, नहीं चर के लिए एक संदर्भ, को पारित कर दिया है CalledProcedure
।
एक सरल उदाहरण यह स्पष्ट रूप से दर्शाएगा:
Sub CalledProcedure(ByRef X As Long, ByVal Y As Long)
X = 321
Y = 654
End Sub
Sub CallingProcedure()
Dim A As Long
Dim B As Long
A = 123
B = 456
Debug.Print "BEFORE CALL => A: " & CStr(A), "B: " & CStr(B)
''Result : BEFORE CALL => A: 123 B: 456
CalledProcedure X:=A, Y:=B
Debug.Print "AFTER CALL = A: " & CStr(A), "B: " & CStr(B)
''Result : AFTER CALL => A: 321 B: 456
End Sub
एक और उदाहरण:
Sub Main()
Dim IntVarByVal As Integer
Dim IntVarByRef As Integer
IntVarByVal = 5
IntVarByRef = 10
SubChangeArguments IntVarByVal, IntVarByRef '5 goes in as a "copy". 10 goes in as a reference
Debug.Print "IntVarByVal: " & IntVarByVal 'prints 5 (no change made by SubChangeArguments)
Debug.Print "IntVarByRef: " & IntVarByRef 'prints 99 (the variable was changed in SubChangeArguments)
End Sub
Sub SubChangeArguments(ByVal ParameterByVal As Integer, ByRef ParameterByRef As Integer)
ParameterByVal = ParameterByVal + 2 ' 5 + 2 = 7 (changed only inside this Sub)
ParameterByRef = ParameterByRef + 89 ' 10 + 89 = 99 (changes the IntVarByRef itself - in the Main Sub)
End Sub
ByRef
डिफ़ॉल्ट संशोधक
यदि कोई पैरामीटर किसी पैरामीटर के लिए निर्दिष्ट नहीं किया जाता है, तो उस पैरामीटर को संदर्भ द्वारा पारित किया जाता है।
Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub
foo
पैरामीटर DoSomething1
और DoSomething2
दोनों में ByRef
को पास करता है।
ध्यान रहे! यदि आप अन्य भाषाओं के अनुभव के साथ VBA में आ रहे हैं, तो यह आपके द्वारा उपयोग किए जा रहे व्यवहार के ठीक विपरीत व्यवहार की संभावना है। कई अन्य प्रोग्रामिंग भाषाओं में (VB.NET सहित), अंतर्निहित / डिफ़ॉल्ट संशोधक मान से पैरामीटर गुजरता है।
संदर्भ से गुजर रहा है
जब कोई मान
ByRef
, तो प्रक्रिया मान का संदर्भ प्राप्त करती है ।Public Sub Test() Dim foo As Long foo = 42 DoSomething foo Debug.Print foo End Sub Private Sub DoSomething(ByRef foo As Long) foo = foo * 2 End Sub
उपरोक्त
Test
प्रक्रिया को कॉल करना 84 को आउटपुट करता है।DoSomething
कोfoo
दिया जाता है और मूल्य के लिए एक संदर्भ प्राप्त होता है, और इसलिए कॉलर के समान मेमोरी एड्रेस के साथ काम करता है।जब एक संदर्भ
ByRef
पारित किया जाता है, तो प्रक्रिया सूचक को एक संदर्भ प्राप्त करती है ।Public Sub Test() Dim foo As Collection Set foo = New Collection DoSomething foo Debug.Print foo.Count End Sub Private Sub DoSomething(ByRef foo As Collection) foo.Add 42 Set foo = Nothing End Sub
उपरोक्त कोड रन-टाइम एरर 91 उठाता है, क्योंकि कॉलर किसी ऑब्जेक्ट के
Count
मेंबर को कॉल कर रहा है, जो अब मौजूद नहीं है, क्योंकिDoSomething
को ऑब्जेक्ट पॉइंटर का संदर्भ दिया गया था और इसे लौटने से पहलेNothing
सौंपा गया था।
मजबूरन ByVal को कॉल साइट पर
कॉल साइट पर कोष्ठकों का उपयोग करके, आप ByRef
को ओवरराइड कर सकते हैं और एक तर्क को पास करने के लिए बाध्य कर सकते हैं ByVal
:
Public Sub Test()
Dim foo As Long
foo = 42
DoSomething (foo)
Debug.Print foo
End Sub
Private Sub DoSomething(ByRef foo As Long)
foo = foo * 2
End Sub
उपरोक्त कोड 42 को आउटपुट करता है, भले ही ByRef
को स्पष्ट रूप से या स्पष्ट रूप से निर्दिष्ट किया गया हो।
ध्यान रहे! इस वजह से, प्रक्रिया कॉल में बाहर के कोष्ठकों का उपयोग करके आसानी से बग का परिचय दिया जा सकता है। प्रक्रिया के नाम और तर्क सूची के बीच व्हाट्सएप पर ध्यान दें:
bar = DoSomething(foo) 'function call, no whitespace; parens are part of args list DoSomething (foo) 'procedure call, notice whitespace; parens are NOT part of args list DoSomething foo 'procedure call does not force the foo parameter to be ByVal
ByVal
मान से गुजरना
जब कोई मान
ByVal
, तो प्रक्रिया मूल्य की एक प्रति प्राप्त करती है ।Public Sub Test() Dim foo As Long foo = 42 DoSomething foo Debug.Print foo End Sub Private Sub DoSomething(ByVal foo As Long) foo = foo * 2 End Sub
उपरोक्त
Test
प्रक्रिया को कॉल करना 42 आउटपुट करता है।DoSomething
कोfoo
दिया जाता है और मूल्य की एक प्रति प्राप्त होती है । प्रतिलिपि को 2 से गुणा किया जाता है, और फिर जब प्रक्रिया से बाहर निकलता है तो उसे छोड़ दिया जाता है; कॉलर की कॉपी कभी नहीं बदली गई थी।जब एक संदर्भ
ByVal
, तो प्रक्रिया सूचक की एक प्रति प्राप्त करती है ।Public Sub Test() Dim foo As Collection Set foo = New Collection DoSomething foo Debug.Print foo.Count End Sub Private Sub DoSomething(ByVal foo As Collection) foo.Add 42 Set foo = Nothing End Sub
उपरोक्त
Test
प्रक्रिया कोDoSomething
आउटपुट 1.DoSomething
कोfoo
दिया जाता है औरCollection
वस्तु के लिए सूचक की एक प्रति प्राप्त करता है । क्योंकिTest
स्कोप मेंfoo
ऑब्जेक्ट वैरिएबल एक ही ऑब्जेक्ट को इंगित करता है,DoSomething
में एक आइटम जोड़ने से आइटम को उसी ऑब्जेक्ट में जोड़ा जाता है। क्योंकि यह पॉइंटर की एक प्रति है, इसकेNothing
भी नहीं के संदर्भ को सेट करने से कॉल करने वाले की स्वयं की प्रति प्रभावितNothing
होती है।