हेलो हैबरा आज हम सीएलआर तंत्र में से एक को देखेंगे जो सीधे सी # डेवलपर्स के लिए सुलभ नहीं है - अपवाद फिल्टर।
मेरे दोस्तों C # प्रोग्रामर्स के बीच एक सर्वेक्षण से पता चला है कि उन्होंने (निश्चित रूप से) इस तंत्र का इस्तेमाल कभी नहीं किया और इसके अस्तित्व के बारे में भी नहीं जानते। इसलिए, मैं लेख के पाठ को पढ़ने के लिए सभी जिज्ञासुओं को आमंत्रित करता हूं।
इसलिए, अपवाद फ़िल्टर एक ऐसा तंत्र है जो एक
catch
पूर्व शर्त बताने की अनुमति देता है कि इस ब्लॉक द्वारा पकड़े जाने के लिए अपवाद को पूरा करना होगा। यह तंत्र
ठीक वैसे ही काम
नहीं करता
है जैसे
catch
अंदर
catch
।
कटौती के तहत VB.NET, F #, CIL और C # कोड है, साथ ही साथ फिल्टर तंत्र को संसाधित करने के लिए विभिन्न डिकंपाइलरों की जांच की जाती है।
जहां अपवाद फिल्टर हैं
अपवाद फ़िल्टर सीएलआर में निर्मित होते हैं और उन तंत्रों में से एक हैं जिनका उपयोग पर्यावरण प्रसंस्करण के अपवादों के दौरान करता है। अनुक्रम इस प्रकार है:

एक उपयुक्त
catch
लिए खोज चरण में
catch
सीएलआर अपवाद हैंडलर के अपने आंतरिक स्टैक को क्रॉल करता है और अपवाद फ़िल्टर भी करता है। ध्यान दें कि
finally
ब्लॉक में कोड निष्पादित होने
से पहले ऐसा होता है। हम इस बिंदु पर बाद में चर्चा करेंगे।
यह VB.NET पर कैसे दिखता है
अपवाद फ़िल्टर मूल रूप से VB.NET भाषा द्वारा समर्थित है। यहाँ इस बात का उदाहरण है कि फ़िल्टर का उपयोग करने वाला कोड कैसा दिखता है:
Sub FilterException() Try Dim exception As New Exception exception.Data.Add("foo", "bar1") Console.WriteLine("Throwing") Throw exception Catch ex As Exception When Filter(ex)
जब इस कोड को निष्पादित किया जाता है, तो निम्न संदेश श्रृंखला जारी की जाएगी:
Throwing Filtering Caught Finally
यह F # में कैसा दिखता है
इस लेख को तैयार करने में, मैंने इंटरनेट पर पाया कि F # अपवाद फ़िल्टर का समर्थन करता है। खैर, इसकी जाँच करें। यहाँ एक नमूना कोड है:
F # पर कोड open System let filter (ex : Exception) = printfn "Filtering" ex.Data.["foo"] :?> string = "bar" let filterException() = try let ex = Exception() ex.Data.["foo"] <- "bar" printfn "Throwing" raise ex with
यह कोड बिना फिल्टर के संकलित होता है, सामान्य
catch [mscorlib]System.Object
। मैं अपवाद फ़िल्टर बनाने के लिए F # कंपाइलर प्राप्त करने में कभी कामयाब नहीं रहा। यदि आप ऐसा करने के वैकल्पिक तरीकों से अवगत हैं, तो टिप्पणी में आपका स्वागत है।
यह CIL में कैसे दिखता है
CIL (सामान्य मध्यवर्ती भाषा) एक .NET मशीन के लिए निम्न-स्तरीय असेंबली भाषा का एक एनालॉग है। संकलित असेंबलियों को इस भाषा में
ilasm
टूल का उपयोग करके अलग किया जा सकता है, और .NET के साथ शिप करने वाले
ilasm
का उपयोग करके वापस इकट्ठा किया जाता है।
यहाँ VB.NET पर कोड का एक टुकड़ा है जैसा कि मैंने इसे
ildasm
में देखा था:
बहुत सारे CIL कोड .method public static void FilterException() cil managed {
जैसा कि आप देख सकते हैं, VB.NET संकलक, निश्चित रूप से CIL के रूप में हमारे कोड को बहुत अधिक चित्रित करता है।
filter
ब्लॉक में हमारी सबसे अधिक रुचि क्या है:
filter {
इसलिए, संकलक ने फ़िल्टर ब्लॉक में एक अपवाद प्रकार की जांच जारी की, साथ ही हमारे फ़ंक्शन को कॉल किया। यदि फ़िल्टर के निष्पादन के अंत में मूल्य
1
स्टैक पर है, तो इस फ़िल्टर के अनुरूप
catch
ब्लॉक निष्पादित किया जाएगा; अन्यथा, नहीं।
यह ध्यान देने योग्य है कि सी # कंपाइलर
filter
ब्लॉक में टाइप चेक नहीं लगाता है, लेकिन एक विशेष संकेत के साथ एक विशेष CIL निर्माण का उपयोग करता है। यही है, सी # कंपाइलर
filter
तंत्र का उपयोग बिल्कुल नहीं करता है।
वैसे, इस ब्लॉक को जेनरेट करने के लिए, आप
ILGenerator.BeginExceptFilterBlock विधि (यदि आप अपना कंपाइलर लिख रहे हैं) का उपयोग कर सकते हैं।
डिकम्पॉइलर में यह कैसा दिखता है
इस खंड में, मैं कई प्रसिद्ध उपकरणों का उपयोग करके परिणामी कोड को विघटित करने की कोशिश करूंगा और देखूंगा कि क्या होता है।
नवीनतम
JetBrains dotPeek 1.1, जब एक फिल्टर के साथ विधानसभा को विघटित करने की कोशिश हो रही है, तो खुशी से निम्नलिखित की सूचना दी:
public static void FilterException() {
.NET रिफलेक्टर 8.2 ने अधिक पर्याप्त रूप से कार्य किया है और C # में कुछ विघटित करने में सक्षम है:
public static void FilterException() { try { Exception exception = new Exception(); exception.Data.Add("foo", "bar"); Console.WriteLine("Throwing"); throw exception; } catch when (?) { Console.WriteLine("Caught"); ProjectData.ClearProjectError(); } finally { Console.WriteLine("Finally"); } }
ठीक है, बुरा नहीं है - यद्यपि कोड संकलित नहीं है, आप इसके द्वारा फ़िल्टर भी देख सकते हैं। यह तथ्य कि फ़िल्टर को डिक्रिप्ट नहीं किया गया था, को C # अनुवादक की कमियों के लिए जिम्मेदार ठहराया जा सकता है। चलिए VB.NET में अनुवादक के साथ भी यही कोशिश करते हैं:
Public Shared Sub FilterException() Try Dim exception As New Exception exception.Data.Add("foo", "bar") Console.WriteLine("Throwing") Throw exception Catch obj1 As Object When (?) Console.WriteLine("Caught") ProjectData.ClearProjectError Finally Console.WriteLine("Finally") End Try End Sub
काश, उसी तरह से प्रयास विफल हो गया - किसी कारण से डिकंपाइलर फ़िल्टरिंग फ़ंक्शन का नाम निर्धारित नहीं कर सका (हालांकि, जैसा कि हमने ऊपर देखा,
ildasm
ने इसका एक बड़ा काम किया है)।
मैं केवल यह मान सकता हूं कि चर्चा किए गए उपकरण .NET4.5 फिल्टर कोड के साथ अच्छी तरह से काम नहीं करते हैं।
यह catch
के शरीर में चेक से कैसे भिन्न होता है
उस कोड के टुकड़े पर विचार करें जो
लगभग VB.NET कोड के समान है:
C # कोड static void FilterException() { try { var exception = new Exception(); exception.Data["foo"] = "bar"; Console.WriteLine("Throwing"); throw exception; } catch (Exception exception) { if (!Filter(exception)) { throw; } Console.WriteLine("Caught"); } } static bool Filter(Exception exception) { return exception.Data["foo"].Equals("bar"); }
अब आइए C # और VB.NET में उदाहरणों के बीच व्यवहार में अंतर खोजने की कोशिश करते हैं। यह काफी सरल है:
throw;
सी में # स्टैक पर लाइन नंबर खो देता है। यदि आप फ़िल्टर को बदलते हैं ताकि यह
false
, तो एप्लिकेशन एक संदेश के साथ क्रैश हो जाएगा
Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown. at CSharpFilter.Program.FilterException() in CSharpFilter\Program.cs:line 25 at CSharpFilter.Program.Main(String[] args) in CSharpFilter\Program.cs:line 9
स्टैक को देखते हुए, एक अपवाद पंक्ति 25 (लाइन
throw;
) पर फेंका गया था, और लाइन 19 पर नहीं (
throw exception;
)। समान शर्तों के तहत VB.NET कोड अपवाद का प्रारंभिक स्थान दिखाता है।
युपीडी। शुरू में, मैंने गलती से लिखा था कि
throw;
पूरे ढेर को खो देता है, लेकिन टिप्पणियों में उन्होंने सुझाव दिया कि यह वास्तव में बिल्कुल नहीं है। स्टैक पर लाइन संख्या के लिए केवल एक मामूली संशोधन है। इसके अलावा, यह मोनो पर नहीं खेलता है - अपवाद स्टैक
throw;
बाद वहां नहीं बदलता है
throw;
(इन विवरणों के लिए धन्यवाद
kekekeks )।
सुरक्षा के बारे में
अपने ब्लॉग में एरिक लिपर्ट
उस स्थिति
पर विचार करते हैं, जहां अपवाद फ़िल्टर दुर्भावनापूर्ण पक्ष को कुछ मामलों में उन्नत विशेषाधिकार के साथ अपने कोड को निष्पादित करने की अनुमति देते हैं।
संक्षेप में: यदि आप कुछ बाहरी और संभावित विनाशकारी कोड के लिए एक अस्थायी विशेषाधिकार वृद्धि का प्रदर्शन कर रहे हैं, तो आप
finally
भरोसा नहीं कर सकते, क्योंकि
finally
ब्लॉक को निष्पादित करने से पहले, कॉल स्टैक के ऊपर स्थित अपवाद फिल्टर को बुलाया जा सकता है (और एक हमलावर इन फिल्टर के कोड में जो चाहे कर सकता है)। याद रखें -
finally
ब्लॉक निष्पादित
होने से
पहले हमेशा सही
catch
ढूंढना होता है।
निष्कर्ष
आज हमने C # में शायद ही कभी सीएलआर प्रोग्रामर में से एक को देखा। मैं खुद VB.NET पर नहीं लिखता, लेकिन मेरा मानना है कि यह जानकारी .NET प्लेटफॉर्म के सभी डेवलपर्स के लिए उपयोगी हो सकती है। ठीक है, यदि आप इस प्लेटफ़ॉर्म के लिए भाषा, संकलक या डीकंपाइलर विकसित कर रहे हैं, तो यह जानकारी आपके लिए विशेष रूप से उपयोगी है।
पुनश्च। कोड, चित्र और लेख पाठ को github:
github.com/ForNeVeR/ClrExceptionForters पर पोस्ट किया गया है।