खोज…
त्रुटि की स्थिति से बचना
जब कोई रनटाइम त्रुटि होती है, तो अच्छे कोड को संभालना चाहिए। सबसे अच्छी त्रुटि से निपटने की रणनीति कोड लिखना है जो त्रुटि स्थितियों की जांच करता है और बस रन कोड को निष्पादित करने से बचता है जिसके परिणामस्वरूप रनटाइम त्रुटि होती है।
रनटाइम त्रुटियों को कम करने में एक प्रमुख तत्व, छोटी प्रक्रियाओं को लिख रहा है जो एक काम करते हैं । कम कारणों वाली प्रक्रियाओं को विफल करना पड़ता है, एक पूरे के रूप में कोड को डीबग करना आसान होता है।
रनटाइम त्रुटि से बचना 91 - ऑब्जेक्ट या ब्लॉक चर के साथ सेट नहीं:
यह त्रुटि तब उठाई जाएगी जब किसी ऑब्जेक्ट का उपयोग उसके संदर्भ को असाइन करने से पहले किया जाता है। एक प्रक्रिया हो सकती है जो एक वस्तु पैरामीटर प्राप्त करती है:
Private Sub DoSomething(ByVal target As Worksheet)
Debug.Print target.Name
End Sub
यदि target
को कोई संदर्भ नहीं दिया गया है, तो उपरोक्त कोड में एक त्रुटि होगी जो आसानी से जाँच से बच जाएगी यदि ऑब्जेक्ट में एक वास्तविक ऑब्जेक्ट संदर्भ है:
Private Sub DoSomething(ByVal target As Worksheet)
If target Is Nothing Then Exit Sub
Debug.Print target.Name
End Sub
यदि target
को एक संदर्भ नहीं सौंपा गया है, तो बिना बताए संदर्भ का उपयोग कभी नहीं किया जाता है, और कोई त्रुटि नहीं होती है।
किसी एक या अधिक पैरामीटर के मान्य नहीं होने पर किसी प्रक्रिया को जल्दी से समाप्त करने का यह तरीका गार्ड क्लॉज कहलाता है।
रनटाइम त्रुटि से बचने 9 - सीमा से बाहर सदस्यता:
यह त्रुटि तब उठाई जाती है जब किसी सरणी को उसकी सीमाओं के बाहर एक्सेस किया जाता है।
Private Sub DoSomething(ByVal index As Integer)
Debug.Print ActiveWorkbook.Worksheets(index)
End Sub
ActiveWorkbook
में वर्कशीट की संख्या से अधिक एक इंडेक्स को देखते हुए, उपरोक्त कोड रनटाइम त्रुटि को बढ़ाएगा। एक साधारण गार्ड क्लॉज इससे बच सकता है:
Private Sub DoSomething(ByVal index As Integer)
If index > ActiveWorkbook.Worksheets.Count Or index <= 0 Then Exit Sub
Debug.Print ActiveWorkbook.Worksheets(index)
End Sub
अधिकांश क्रम त्रुटियों ध्यान से मूल्यों इससे पहले कि हम उन्हें इस्तेमाल हम प्रयोग कर रहे पुष्टि करने, और तदनुसार एक सरल का उपयोग करते हुए एक और निष्पादन पथ पर शाखाओं में से बचा जा सकता If
में गार्ड खंड में कोई धारणाएं बनाता है कि और एक प्रक्रिया के मानकों की पुष्टि करता है, या यहाँ तक - बयान बड़ी प्रक्रियाओं का शरीर।
त्रुटि कथन पर
यहां तक कि गार्ड क्लॉस के साथ, कोई भी वास्तविक रूप से हमेशा सभी संभावित त्रुटि स्थितियों के लिए जिम्मेदार नहीं हो सकता है जो एक प्रक्रिया के शरीर में उठाए जा सकते हैं। जब भी कोई अनपेक्षित त्रुटि रनटाइम पर होती है, तो On Error GoTo
स्टेटमेंट VBA को एक लाइन लेबल पर कूदने और "एरर हैंडलिंग मोड" दर्ज करने का निर्देश देता है। एक त्रुटि को संभालने के बाद, कोड फिर से शुरू हो सकता है "सामान्य" निष्पादन में Resume
से Resume
।
लाइन लेबल सबरूटीन्स निरूपित: क्योंकि सबरूटीन्स विरासत बुनियादी कोड से ही शुरू और का उपयोग करता है GoTo
और GoSub
कूदता है और Return
"मुख्य" दिनचर्या में वापस कूद करने के बयान, यह काफी आसान स्पेगेटी कोड मुश्किल से पालन लिखने के लिए अगर चीजें कड़ाई से संरचित नहीं कर रहे हैं । इस कारण से, यह सबसे अच्छा है:
- एक प्रक्रिया में एक और केवल एक त्रुटि-हैंडलिंग सबरूटीन है
- त्रुटि से निपटने सबरूटिन केवल एक त्रुटि स्थिति में चलता है
इसका मतलब है कि एक प्रक्रिया जो अपनी त्रुटियों को संभालती है, उसे इस तरह संरचित किया जाना चाहिए:
Private Sub DoSomething()
On Error GoTo CleanFail
'procedure code here
CleanExit:
'cleanup code here
Exit Sub
CleanFail:
'error-handling code here
Resume CleanExit
End Sub
रणनीतियों को संभालने में त्रुटि
कभी-कभी आप विभिन्न कार्यों के साथ विभिन्न त्रुटियों को संभालना चाहते हैं। उस स्थिति में आप वैश्विक Err
ऑब्जेक्ट का निरीक्षण करेंगे, जिसमें उस त्रुटि के बारे में जानकारी होगी जिसे उठाया गया था - और तदनुसार कार्य करें:
CleanExit:
Exit Sub
CleanFail:
Select Case Err.Number
Case 9
MsgBox "Specified number doesn't exist. Please try again.", vbExclamation
Resume
Case 91
'woah there, this shouldn't be happening.
Stop 'execution will break here
Resume 'hit F8 to jump to the line that raised the error
Case Else
MsgBox "An unexpected error has occurred:" & vbNewLine & Err.Description, vbCritical
Resume CleanExit
End Select
End Sub
एक सामान्य दिशानिर्देश के रूप में, संपूर्ण सबरूटीन या फ़ंक्शन के लिए त्रुटि हैंडलिंग चालू करने पर विचार करें, और इसके दायरे में आने वाली सभी त्रुटियों को संभाल सकते हैं। यदि आपको कोड के छोटे सेक्शन में केवल त्रुटियों को संभालने की आवश्यकता है - एक ही स्तर पर त्रुटि हैंडलिंग चालू और बंद करें:
Private Sub DoSomething(CheckValue as Long)
If CheckValue = 0 Then
On Error GoTo ErrorHandler ' turn error handling on
' code that may result in error
On Error GoTo 0 ' turn error handling off - same level
End If
CleanExit:
Exit Sub
ErrorHandler:
' error handling code here
' do not turn off error handling here
Resume
End Sub
पंक्ति संख्याएँ
VBA विरासत-शैली (जैसे QBASIC) पंक्ति संख्याओं का समर्थन करता है। अंतिम त्रुटि को उठाने वाले लाइन नंबर की पहचान करने के लिए Erl
हिडन प्रॉपर्टी का उपयोग किया जा सकता है। यदि आप लाइन नंबर का उपयोग नहीं कर रहे हैं, तो Erl
केवल 0 पर वापस लौटेगा।
Sub DoSomething()
10 On Error GoTo 50
20 Debug.Print 42 / 0
30 Exit Sub
40
50 Debug.Print "Error raised on line " & Erl ' returns 20
End Sub
यदि आप लाइन नंबरों का उपयोग कर रहे हैं , लेकिन लगातार नहीं, तो त्रुटि को उठाने वाले निर्देश से पहले Erl
अंतिम पंक्ति संख्या वापस कर देंगे।
Sub DoSomething()
10 On Error GoTo 50
Debug.Print 42 / 0
30 Exit Sub
50 Debug.Print "Error raised on line " & Erl 'returns 10
End Sub
ध्यान रखें कि Erl
केवल Integer
परिशुद्धता है, और चुपचाप अतिप्रवाह होगा। इसका मतलब यह है कि पूर्णांक सीमा के बाहर लाइन संख्या गलत परिणाम देगी:
Sub DoSomething()
99997 On Error GoTo 99999
99998 Debug.Print 42 / 0
99999
Debug.Print Erl 'Prints 34462
End Sub
लाइन नंबर काफी प्रासंगिक नहीं है क्योंकि यह कथन त्रुटि का कारण बना, और नंबरिंग लाइन जल्दी थकाऊ हो जाती है और काफी रखरखाव के अनुकूल नहीं है।
कीवर्ड फिर से शुरू करें
त्रुटि से निपटने वाला सबरूटीन या तो होगा:
- प्रक्रिया के अंत तक, जिस स्थिति में निष्पादन कॉलिंग प्रक्रिया में शुरू होता है।
- या, उसी प्रक्रिया के अंदर निष्पादन को फिर से शुरू करने के लिए
Resume
कीवर्ड का उपयोगResume
।
Resume
कीवर्ड का उपयोग कभी-कभी उप-त्रुटि से निपटने में त्रुटि के अंदर किया जाना चाहिए, क्योंकि यदि VBA त्रुटि स्थिति में बिना Resume
, तो रनटाइम त्रुटि 20 "त्रुटि के बिना फिर से शुरू करें" को उठाया जाता है।
एक त्रुटि से निपटने वाले सबरूटीन को Resume
से Resume
कीवर्ड का उपयोग करने के कई तरीके हो सकते हैं:
- अकेले उपयोग किया गया
Resume
, उस कथन पर निष्पादन जारी है जो त्रुटि का कारण बना । यदि वास्तव में ऐसा करने से पहले त्रुटि को नियंत्रित नहीं किया जाता है, तो उसी त्रुटि को फिर से उठाया जाएगा, और निष्पादन एक अनंत लूप में प्रवेश कर सकता है। -
Resume Next
उस स्टेटमेंट पर तुरंत स्टेटमेंट जारी करता है, जो उस त्रुटि के कारण होता है। यदि वास्तव में ऐसा करने से पहले त्रुटि को नियंत्रित नहीं किया जाता है, तो निष्पादन को संभावित रूप से अमान्य डेटा के साथ जारी रखने की अनुमति मिलती है, जिसके परिणामस्वरूप तार्किक त्रुटियां और अप्रत्याशित व्यवहार हो सकता है। -
Resume [line label]
निर्दिष्ट लाइन लेबल (या लाइन नंबर, यदि आप विरासत शैली लाइन संख्या का उपयोग कर रहे हैं) पर निष्पादन जारी है। यह आमतौर पर प्रक्रिया से बाहर निकलने से पहले कुछ सफाई कोड को निष्पादित करने की अनुमति देता है, जैसे कि कॉल करने वाले के लौटने से पहले डेटाबेस कनेक्शन बंद करना सुनिश्चित करता है।
त्रुटि फिर से शुरू पर
On Error
स्टेटमेंट में ही VBA रनटाइम को सभी त्रुटियों को प्रभावी रूप से अनदेखा करने के लिए Resume
से Resume
करने के लिए Resume
कीवर्ड का उपयोग किया जा सकता है।
यदि वास्तव में ऐसा करने से पहले त्रुटि को नियंत्रित नहीं किया जाता है, तो निष्पादन को संभावित रूप से अमान्य डेटा के साथ जारी रखने की अनुमति मिलती है, जिसके परिणामस्वरूप तार्किक त्रुटियां और अप्रत्याशित व्यवहार हो सकता है ।
ऊपर दिए गए जोर पर पर्याप्त जोर नहीं दिया जा सकता है। त्रुटि को फिर से शुरू करें पर सभी त्रुटियों को प्रभावी ढंग से अनदेखा करता है और उन्हें कालीन के नीचे धक्का देता है । एक प्रोग्राम जो रनटाइम त्रुटि के साथ अमान्य इनपुट देता है, एक से एक बेहतर प्रोग्राम है जो अज्ञात / अनजाने डेटा के साथ चलता रहता है - केवल इसलिए कि बग अधिक आसानी से पहचाने जाने योग्य है। On Error Resume Next
आसानी से कीड़े छिपा सकते हैं।
On Error
स्टेटमेंट प्रक्रिया-स्कोप है - इसीलिए आम तौर पर केवल एक ही होना चाहिए, एक दिए प्रक्रिया में सिंगल On Error
स्टेटमेंट।
हालाँकि कभी-कभी एक त्रुटि स्थिति से बचा नहीं जा सकता है, और एक त्रुटि-हैंडलिंग सबरूटीन पर कूदना केवल Resume Next
से Resume Next
करने के लिए है बस सही नहीं लगता है। इस विशिष्ट मामले में, ज्ञात-से-संभवतया-विफल कथन को दो On Error
बीच लपेटा जा सकता है:
On Error Resume Next
[possibly-failing statement]
Err.Clear 'resets current error
On Error GoTo 0
On Error GoTo 0
अनुदेश वर्तमान प्रक्रिया में त्रुटि से निपटने में रीसेट करता है, जैसे कि रनटाइम त्रुटि पैदा करने वाला कोई भी निर्देश उस प्रक्रिया के भीतर बंद हो जाएगा और इसके बजाय कॉल स्टैक को पारित कर दिया जब तक कि यह एक सक्रिय त्रुटि हैंडलर द्वारा पकड़ा न जाए। यदि कॉल स्टैक में कोई सक्रिय त्रुटि हैंडलर नहीं है, तो इसे एक अनहेल्ड अपवाद के रूप में माना जाएगा।
Public Sub Caller()
On Error GoTo Handler
Callee
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Caller."
End Sub
Public Sub Callee()
On Error GoTo Handler
Err.Raise 1 'This will be handled by the Callee handler.
On Error GoTo 0 'After this statement, errors are passed up the stack.
Err.Raise 2 'This will be handled by the Caller handler.
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Callee."
Resume Next
End Sub
कस्टम त्रुटियां
अक्सर एक विशेष वर्ग लिखते समय, आप चाहते हैं कि यह अपनी विशिष्ट त्रुटियों को बढ़ाए, और आप अपनी कस्टम त्रुटियों को संभालने के लिए उपयोगकर्ता / कॉलिंग कोड के लिए एक स्वच्छ तरीका चाहते हैं। एक समर्पित Enum
प्रकार को परिभाषित करके इसे प्राप्त करने का एक साफ तरीका है:
Option Explicit
Public Enum FoobarError
Err_FooWasNotBarred = vbObjectError + 1024
Err_BarNotInitialized
Err_SomethingElseHappened
End Enum
vbObjectError
निर्मित निरंतर का उपयोग करना सुनिश्चित करता है कि कस्टम त्रुटि कोड आरक्षित / मौजूदा त्रुटि कोड के साथ ओवरलैप न हो। केवल स्पष्ट रूप से निर्दिष्ट किया जा करने के लिए पहली enum मूल्य की जरूरत है, प्रत्येक के अंतर्निहित मूल्य के लिए Enum
सदस्य है 1
, पिछले सदस्य से बड़ा तो के अंतर्निहित कीमत Err_BarNotInitialized
परोक्ष है vbObjectError + 1025
।
अपनी स्वयं की रनटाइम त्रुटियों को उठाना
Err.Raise
स्टेटमेंट का उपयोग करके रनटाइम त्रुटि को उठाया जा सकता है, इसलिए कस्टम Err_FooWasNotBarred
त्रुटि को निम्नानुसार उठाया जा सकता है:
Err.Raise Err_FooWasNotBarred
Err.Raise
पद्धति कस्टम Description
और Source
पैरामीटर भी ले सकती है - इस कारण से यह एक अच्छा विचार है कि प्रत्येक कस्टम त्रुटि का विवरण रखने के लिए स्थिरांक को परिभाषित करना भी है:
Private Const Msg_FooWasNotBarred As String = "The foo was not barred."
Private Const Msg_BarNotInitialized As String = "The bar was not initialized."
और फिर प्रत्येक त्रुटि को बढ़ाने के लिए एक समर्पित निजी विधि बनाएं:
Private Sub OnFooWasNotBarredError(ByVal source As String)
Err.Raise Err_FooWasNotBarred, source, Msg_FooWasNotBarred
End Sub
Private Sub OnBarNotInitializedError(ByVal source As String)
Err.Raise Err_BarNotInitialized, source, Msg_BarNotInitialized
End Sub
तब वर्ग का कार्यान्वयन त्रुटि को बढ़ाने के लिए इन विशिष्ट प्रक्रियाओं को कॉल कर सकता है:
Public Sub DoSomething()
'raises the custom 'BarNotInitialized' error with "DoSomething" as the source:
If Me.Bar Is Nothing Then OnBarNotInitializedError "DoSomething"
'...
End Sub
क्लाइंट कोड तब Err_BarNotInitialized
को संभाल Err_BarNotInitialized
क्योंकि यह अपनी त्रुटि-हैंडलिंग Err_BarNotInitialized
अंदर कोई अन्य त्रुटि होगी।
नोट: विरासत Error
कीवर्ड का उपयोग Err.Raise
स्थान पर भी किया जा सकता है, लेकिन यह अप्रचलित / अस्वीकृत है।