catch Clause
catch Clause का मुख्य काम Exceptions को Handle करना होता है, क्योंकि जो भी Exception Generate होता है, उस Exception से सम्बंधित Object को catch Block ही Catch करता है और सम्बंधित Exception को Handle करता है। catch Block को हम अपनी जरूरत के आधार पर निम्नानुसार तीन Formats में Use कर सकते हैं:
catch { Statements; }
जब हम इस Format में catch Block को Specify करते हैं, तो try Block से जो भी Exception Trigger होता है, हर उस Exception को Handle करने के लिए यही catch Block Execute होता है।
catch ( ExceptionType ) { Statements; }
जब हम इस Format में catch Block को Specify करते हैं, तो try Block से ExceptionType के Exception को Handle करने के लिए ये catch Block Execute होता है।
catch ( ExceptionType ExceptionVariable) { Statements; }
जब हम इस Format में catch Block को Specify करते हैं, तो try Block से ExceptionType के Exception को Handle करने के लिए ये catch Block Execute होता है। साथ ही Exception से सम्बंधित विभिन्न प्रकार की Information जिस Exception Object में Actually Stored रहती है, उस Heap Area Memory को ExceptionVariable में Stored Pointer द्वारा Reference किया जा सकता है, जिसे catch Block में Exception से सम्बंधित जानकारियों को Access करने के लिए Use किया जा सकता है।
उदाहरण के लिए यदि हम अपने पिछले Program में ही इस तीसरे Format को Use करें, तो Throw होने वाले Exception Object की विभिन्न Properties को हम catch Block में निम्नानुसार तरीके से Use कर सकते हैं:
File Name: AccessingExceptionObjectProperties.cs using System; namespace CSharpExceptionHandling { class ExceptionBasics { static void Main(String[] arg) { int x = 10, y = 0; try { x /= y; Console.WriteLine("X: " + x); } catch (Exception exp) { Console.WriteLine("Message: " + exp.Message); Console.WriteLine("Source: " + exp.Source); Console.WriteLine("StackTrace: " + exp.StackTrace); Console.WriteLine("Data: " + exp.Data); Console.WriteLine("InnerExceptoin: " + exp.InnerExceptoin); } } } } // Output: Message: Attempted to divide by zero. Source: AccessingExceptionObjectProperties StackTrace: at CSharpExceptionHandling.ExceptionBasics.Main(String[] arg) Data: System.Collections.ListDictionaryInternal InnerException:
catch Class Block का मुख्य उद्देश्य Generate होने वाली किसी भी Error को Elegant यानी Well Designed तरीके से Handle करना होता है। यदि catch Clause कोई Parameter Accept करता है, तो Parameter के रूप में Specified Exception Variable उस Exception Object को Reference करता है, जिसे हम Generate होने वाली Error को Inspect करने के लिए Use कर सकते हैं।
जबकि यदि Exception किसी पिछले Error की वजह से Trigger हो रहा हो, तो उस पिछले Error की जानकारी इस Exception Object की InnerException Property में होती है। एक try Statement के साथ कई catch Clause को Specify किया जा सकता है, जबकि हर catch Block try Block से Generate होने वाली विभिन्न प्रकार की Errors को ही Handle करने का काम करता है।
जब कोई Error Trigger होता है, तो हमारा System सभी catch Blocks में से Best Appropriate catch Block को Exception को Handle करने के लिए Search करके Execute करता है।
उदाहरण के लिए यदि हम NullReferenceException Class से Derived किसी Exception Class को Define करते हैं, तो हमारे द्वारा Defined Derived Type को NullReferenceException Type के Exception को Handle करने वाले catch Block से पहले Specify करना चाहिए। क्योंकि Base Class का catch Block का Parameter अपने किसी भी Derived Class के Reference को Hold कर सकता है।
इसलिए यदि हम Derived Class से पहले Base Class के Exception Type के catch Block को Specify करेंगे, तो Base Class का Reference, Derived Class के Exception Object को Catch कर लेगा और Compiler कभी भी Derived Class के Exception Handling catch Block में नहीं पहुंचेगा।
इसी तरह से यदि विभिन्न catch Blocks में से कोई General catch Block हो, तो उसे अन्तिम catch Block की तरह ही Define करना चाहिए। क्योंकि General catch Block, try Block द्वारा Generate होने वाली किसी भी तरह की Error को Handle करने में सक्षम होता है।
अत: यदि General catch Block को Special catch Block से पहले Specify कर दिया जाए और try Block द्वारा यदि कोई Special Exception भी Generate हो तथा उस Special Exception को Handle करने के लिए Special catch Block भी Specify किया गया होगा, तब भी वह General catch Block ही Execute होगा, जो कि नहीं होना चाहिए।
finally Block
finally Block एक ऐसा Code Block होता है, जो try Block द्वारा चाहे Exception हो, चाहे न हो, जरूर Execute होता है। इसलिए सामान्यत: finally Block में उन Codes को लिखा जाता है, जिन्हें किसी भी स्थिति में Execute करना जरूरी होता है।
उदाहरण के लिए जब हम try Block में किसी File को Open करते हैं, तो उसे Compulsory रूप से Close करना जरूरी होता है। इसलिए File Close करने के Code को हमेंशा finally Block में लिखा जाता है।
इस तरह से यदि हम Exception Handling Mechanism के सभी Elements try, catch व finally को Use करने का Syntax Create करें, तो ये कुछ निम्न चित्रानुसार होगा:
जब किसी Program में कोई Exception Raise होता है, तो Computer System इस बात को Search करता है कि उस Exception को Handle करने के लिए कोई Exception Handler Specify किया गया है या नहीं। यदि Exception Handler Specify किया गया हो, तो हमारा Computer System निम्न चित्रानुसार उस Exception Handler की Searching करता है:
यानी यदि Exception try Block में Trigger होता है, तो System उस Exception को Handle करने से सम्बंधित Best Appropriate Error Handler catch Block को Search करता है। यदि उपयुक्त Exception Handler मिल जाता है, तो System उस Exception Handler को Execute कर देता है, साथ ही finally Block को भी Execute करता है और यदि Exist हो तो अन्य Codes को भी Execute करता है।
लेकिन यदि उस Particular Exception को Handle करने के लिए Appropriate Exception Handler Exist न हो, तो भी हमारा Operating System finally Block को तो Execute करता ही है। यानी जब हम हमारे Program में Exception Handling Mechanism को Use करते हैं, तो हमारा Program किसी स्थिति में Crash होकर Halt या Hang नहीं होता।
लेकिन यदि Exception Generate करने वाले Code को try Block के बीच Define न किया गया हो, या try Block से Generate होने वाले Exception को उपयुक्त तरीके से Handle करने के लिए Appropriate catch Block Define न किया गया हो, तो System स्वयं ही Call Stack में Downside में किसी अन्य Exception Handler की Searching करता है, जो कि Trigger होने वाले Exception को Handle कर सके। Call Stack के माध्यम से Exception Handling की इस प्रक्रिया को हम निम्न चित्र द्वारा आसानी से समझ सकते हैं:
यानी किसी भी Programming Language में जब कोई Method Call होता है, तो उस Method की Information Memory के Stack में Store हो जाती है। फिर यदि वह Method किसी अन्य Method को Call करता है, तो उस दूसरे Method की Calling Information भी Stack के Top पर Store हो जाती और जैसाकि हम उपरोक्त चित्र में देख सकते हैं कि ये प्रक्रिया Continually चलती रहती है।
इस चित्र के अनुसार Left Side में Call होने वाले Methods को Define किया गया है, जबकि Right Side में Call Stack को दर्शाया गया है। चित्र के अनुसार Method2 को Method1 के try Block में Call किया गया है।
इसलिए यदि Method2 के try Block में कोई Exception Trigger होता है, तो System सबसे पहले इस बात को Check करता है कि Method2 के साथ कोई ऐसा Exception Handler है या नहीं, जो कि Method2 के try Block से Generate होने वाले Exception को Handle कर सके।
यदि Method2 के साथ ऐसा कोई Exception Handler होता है, तो System उस Exception Handler को Execute कर देता है और Program को Normal तरीके से Continually Run कर देता है।
लेकिन यदि Method2 के साथ ऐसा कोई Exception Handler न हो, तो System Call Stack के Downside में Method2 द्वारा Generate होने वाले Exception को Handle करने के लिए Appropriate Method की Searching करता है।
यदि Method2 से Generate होने वाले Exception को Handle करने के लिए Method1 के साथ कोई उपयुक्त catch Block Associated हो, तो System Control फिर से Call Stack के Top पर चला जाता है, जो कि Method2 होता है।
क्योंकि Exception Method2 के try Block में Trigger हुआ था और Control फिर से Method2 के Call Stack में पहुंचकर Method2 के finally Block को Execute करने के बाद System Control Method2 को Call Stack से POP कर देता है तथा Method1 के catch Clause को Execute करने के बाद Mehtod1 के finally Block को Execute करता है।
लेकिन यदि Method2 के try Block से Generate होने वाले Exception को Handle करने से सम्बंधित उपयुक्त Exception Handler catch Block, Method1 में भी न हो, तो System Control उस Exception को Handle करने के लिए Call Stack के और Downside में Appropriate Exception Handler की Searching करता है और ये प्रक्रिया तब तक चलती रहती है, जब तक कि Call Stack के सभी Methods के catch Block को Exception Handling के लिए Check नहीं कर लिया जाता और किसी न किसी Appropriate Exception Handler को Execute नहीं कर दिया जाता।
Exception Handling की पूरी प्रक्रिया से सम्बंधित Algorithm को हम निम्न चित्रानुसार Show कर सकते हैं:
इस पूरे Exception Handling Mechanism को Use करते हुए हम निम्नानुसार एक Program Create कर सकते हैं और विभिन्न Exception Handling Concepts को आसानी से Implement करते हुए समझ सकते हैं:
File Name: ExceptionHandlingMechanism.cs using System; namespace CSharpExceptionHandling { class Program { static void Main() { MyClass MCls = new MyClass(); try { MCls.Method1(); } catch (DivideByZeroException e) { Console.WriteLine("{0} in catch clause of Main()", e.Message); } finally { Console.WriteLine("finally clause in Main()"); } Console.WriteLine("After try statement in Main."); Console.WriteLine(" -- Keep running."); } } class MyClass { public void Method1() { try { Method2(); } catch (System.NullReferenceException) { Console.WriteLine("catch clause in Method1()"); } finally { Console.WriteLine("finally clause in Method1()"); } } void Method2() { int x = 10, y = 0; try { x /= y; } catch (System.IndexOutOfRangeException) { Console.WriteLine("catch clause in Method2()"); } finally { Console.WriteLine("finally clause in Method2()"); } } } } // Output: finally clause in Method2() finally clause in Method1() Attempted to divide by zero. in catch clause of Main() finally clause in Main() After try statement in Main. -- Keep running.
इस Program में सबसे पहले Main() Method, Method1() को Call करता है जो कि Internally Method2() को Call करता है। परिणामस्वरूप Method2() के Execution से DivideByZeroException Trigger होता है।
इस Exception के Generate होते ही Program Control Method2() के cache Block को Matching Exception Hander के लिए Search करता है। हालांकि Method2() के साथ IndexOutOfRangeException Type के Exception को Handle करने के लिए एक catch Block Define किया गया है, लेकिन DivideByZeroException Type के Exception को Handle करने के लिए Method2() में कोई catch Block Define नहीं किया गया है।
इसलिए Program Control Method2() द्वारा Trigger होने वाली Exception को Handle करने के लिए Call Stack के Downside में Move करता है, जहां Method1() के साथ Associated विभिन्न catch Blocks को DivideByZeroException Type की Exception को Handle करने के लिए Matching catch Block को Search किया जाता है।
चूंकि Method1() के साथ भी कोई ऐसा catch Block Define नहीं किया गया है, जो कि DivideByZeroException Type के Exception को Handle कर सके, इसलिए Program Control Call Stack में और Downside में Move करता है, जहां उसे Main() Method के साथ Associated एक ऐसा Matching catch Block प्राप्त होता है, जिसमें DivideByZeroException को Handle करने के लिए Exception Handler लिखा गया है।
हालांकि Method2() द्वारा Generated Exception को Handle करने के लिए Appropriate Matching catch Block प्राप्त हो चुका है, फिर भी Program Control उस catch Block को Execute नहीं करता बल्कि Call Stack के Upside में फिर से Method2() में जाता है और Method2() के Finally Block को Execute करके Method2() को Stack से POP करता है।
अब Program Control Method1() का finally() Block Execute करता है और Method1() के finally Block को Execute करने के बाद Method1() को भी Call Stack से POP करता है और अन्त में Program Control फिर से Main() Method में आता है और Matching catch Block को Execute करता है।
catch Block को Execute करने के बाद भी Program का अन्त नहीं हो जाताए बल्कि Program Control Program को Continue रखता है और Main() Method के try Block के Statements का Execution करता है।
इस तरह से .NET Framework के Exception Handling Mechanism का प्रयोग करके हम ऐसे Programs Create करने की क्षमता प्राप्त करते हैं, जो कि Exception की स्थिति में Crash नहीं होते, बल्कि Exception को Handle करने के बाद भी Normal तरीके से Program को Continue रखते हैं। (C# try catch finally)
ये Article इस वेबसाईट पर Selling हेतु उपलब्ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी।
C#.NET in Hindi | Page:908 | Format: PDF