प्रॉपर्टी गेट्टर या सेटर के भीतर अपवाद को फेंकना कब उचित है? यह कब उचित नहीं है? क्यों? इस विषय पर बाहरी दस्तावेज़ों के लिंक सहायक होंगे ... Google आश्चर्यजनक रूप से बहुत कम निकला।
प्रॉपर्टी गेट्टर या सेटर के भीतर अपवाद को फेंकना कब उचित है? यह कब उचित नहीं है? क्यों? इस विषय पर बाहरी दस्तावेज़ों के लिंक सहायक होंगे ... Google आश्चर्यजनक रूप से बहुत कम निकला।
जवाबों:
Microsoft की http://msdn.microsoft.com/en-us/library/ms229006.aspx पर प्रॉपर्टी डिज़ाइन करने के बारे में अपनी सिफारिशें हैं
अनिवार्य रूप से, वे सलाह देते हैं कि संपत्ति पाने वाले हल्के सहायक हों जो हमेशा कॉल करने के लिए सुरक्षित हों। यदि वे अपवादों को फेंकने की आवश्यकता हो तो वे कुछ नया करने की सलाह देते हैं। बसने वालों के लिए वे संकेत देते हैं कि अपवाद एक उपयुक्त और स्वीकार्य त्रुटि से निपटने की रणनीति है।
इंडेक्सर्स के लिए, Microsoft इंगित करता है कि यह दोनों गेटर्स के लिए स्वीकार्य है और अपवादों को फेंकने के लिए बसता है। और वास्तव में, .NET लाइब्रेरी में कई इंडेक्सर्स ऐसा करते हैं। सबसे आम अपवाद है ArgumentOutOfRangeException
।
कुछ बहुत अच्छे कारण हैं कि आप संपत्ति पाने वालों में अपवाद क्यों नहीं फेंकना चाहते हैं:
obj.PropA.AnotherProp.YetAnother
- इस तरह के सिंटैक्स के साथ यह तय करना समस्याग्रस्त हो जाता है कि अपवाद पकड़ने वाले बयानों को कहां इंजेक्ट किया जाए।एक साइड नोट के रूप में, किसी को पता होना चाहिए कि सिर्फ इसलिए कि एक संपत्ति एक अपवाद को फेंकने के लिए डिज़ाइन नहीं की गई है, इसका मतलब यह नहीं है कि यह नहीं होगा; यह आसानी से कॉलिंग कोड हो सकता है जो करता है। यहां तक कि एक नई वस्तु (एक स्ट्रिंग की तरह) को आवंटित करने का सरल कार्य अपवाद हो सकता है। आपको हमेशा अपने कोड को रक्षात्मक रूप से लिखना चाहिए और आपके द्वारा आह्वान किए गए कुछ से अपवादों की अपेक्षा करनी चाहिए।
बसने वालों से अपवाद फेंकने में कुछ भी गलत नहीं है। आखिर, यह बताने का बेहतर तरीका क्या है कि मूल्य किसी संपत्ति के लिए मान्य नहीं है?
गेटर्स के लिए, यह आम तौर पर होता है, और जिसे बहुत आसानी से समझाया जा सकता है: एक संपत्ति पाने वाला, सामान्य तौर पर, किसी वस्तु की वर्तमान स्थिति की रिपोर्ट करता है; इस प्रकार, केवल एक मामला जहां यह फेंकने के लिए उचित है जब राज्य अमान्य है। लेकिन यह आमतौर पर आपकी कक्षाओं को डिजाइन करने के लिए एक अच्छा विचार माना जाता है, जैसे कि एक अवैध वस्तु को शुरू में प्राप्त करना संभव नहीं है, या इसे सामान्य तरीकों के माध्यम से अमान्य स्थिति में डाल दिया जाता है (यानी, हमेशा निर्माणकर्ताओं में पूर्ण आरंभ सुनिश्चित करें, और राज्य की वैधता और वर्ग के आक्रमणकारियों के संबंध में तरीकों को अपवाद-सुरक्षित बनाने का प्रयास करें)। जब तक आप उस नियम से चिपके रहते हैं, तब तक आपकी संपत्ति पाने वाले को कभी भी ऐसी स्थिति में नहीं जाना चाहिए, जहां उन्हें अमान्य स्थिति की सूचना देनी पड़े, और इस तरह कभी नहीं फेंकना चाहिए।
एक अपवाद है जिसे मैं जानता हूं, और यह वास्तव में एक प्रमुख है: किसी भी वस्तु को लागू करना IDisposable
। Dispose
किसी वस्तु को अमान्य स्थिति में लाने के तरीके के रूप में विशेष रूप से अभिप्रेत है, और ObjectDisposedException
उस मामले में उपयोग किए जाने के लिए एक विशेष अपवाद वर्ग भी है । ObjectDisposedException
किसी भी वर्ग के सदस्य से, संपत्ति प्राप्त करने वाले (और Dispose
खुद को छोड़कर ) सहित, वस्तु के निपटान के बाद फेंकना पूरी तरह से सामान्य है ।
IDisposable
बाद एक सभी सदस्यों को बेकार कर दिया जाना चाहिए Dispose
। यदि किसी सदस्य को आमंत्रित करने के लिए एक संसाधन के उपयोग की आवश्यकता होती है, जो Dispose
अनुपलब्ध हो गया है (जैसे सदस्य एक स्ट्रीम से डेटा पढ़ेगा जिसे बंद कर दिया गया है) तो सदस्य को ObjectDisposedException
लीक करने के बजाय फेंक देना चाहिए ArgumentException
, लेकिन यदि किसी के पास एक ऐसा गुण है जो प्रतिनिधित्व करते हैं कुछ क्षेत्रों में मान, ऐसे गुणों को निपटान के बाद पढ़ने की अनुमति देना कहीं अधिक उपयोगी होगा (अंतिम टाइप किए गए मानों की पैदावार) की अपेक्षा ...
Dispose
जब तक इस तरह के सभी गुणों को पढ़ लिया गया है तब तक के लिए स्थगित कर दिया जाए। कुछ मामलों में जहां एक धागा किसी वस्तु पर अवरुद्ध रीडिंग का उपयोग कर सकता है, जबकि दूसरा इसे बंद कर देता है, और जहां डेटा किसी भी समय पहले आ सकता है Dispose
, यह Dispose
आने वाले डेटा को काटने के लिए सहायक हो सकता है , लेकिन पहले से प्राप्त डेटा को पढ़ने की अनुमति देता है। किसी के बीच Close
और Dispose
उन स्थितियों में एक कृत्रिम अंतर को बाध्य नहीं करना चाहिए जहां किसी को भी मौजूद होने की आवश्यकता नहीं होगी।
Get...
बजाय एक विधि के रूप में बेहतर है । यहां एक अपवाद तब है जब आपको एक मौजूदा इंटरफ़ेस लागू करना होगा जिसके लिए आपको एक संपत्ति प्रदान करनी होगी।
यह लगभग एक गॉटर पर कभी उचित नहीं होता है, और कभी-कभी एक सेटर पर उपयुक्त होता है।
इन प्रकार के प्रश्नों के लिए सबसे अच्छा संसाधन "फ्रेमवर्क गाइडलाइन्स" है, जो सेलविना और अब्राम्स द्वारा बनाई गई हैं; यह एक बाउंड बुक के रूप में उपलब्ध है, और इसके बड़े हिस्से ऑनलाइन भी उपलब्ध हैं।
5.2 खंड से: संपत्ति डिजाइन
एवीओआईडी संपत्ति पाने वालों से अपवादों को फेंकती है। संपत्ति पाने वालों को सरल ऑपरेशन होना चाहिए और उनमें पूर्व शर्त नहीं होनी चाहिए। यदि कोई गेटर अपवाद छोड़ सकता है, तो संभवतः इसे एक विधि के रूप में फिर से डिज़ाइन किया जाना चाहिए। ध्यान दें कि यह नियम इंडेक्सरों पर लागू नहीं होता है, जहां हम तर्कों को मान्य करने के परिणामस्वरूप अपवादों की अपेक्षा करते हैं।
ध्यान दें कि यह दिशानिर्देश केवल संपत्ति पाने वालों पर लागू होता है। प्रॉपर्टी सेटर में अपवाद फेंकना ठीक है।
ObjectDisposedException
एक बार ऑब्जेक्ट को Dispose()
कॉल करने पर विचार करना चाहिए और कुछ बाद में एक संपत्ति मूल्य के लिए पूछता है? ऐसा लगता है कि मार्गदर्शन को "संपत्ति पाने वालों से अपवादों को फेंकने से बचना चाहिए, जब तक कि वस्तु का निपटारा नहीं किया गया हो, जिस स्थिति में आपको ऑब्जेक्टडिपीस्ड एक्सपटेशन फेंकने पर विचार करना चाहिए"।
अपवादों के लिए एक अच्छा तरीका यह है कि वे अपने लिए और अन्य डेवलपर्स के लिए दस्तावेज़ कोड का उपयोग करें:
अपवाद असाधारण कार्यक्रम राज्यों के लिए होना चाहिए। इसका मतलब यह है कि आप जहां चाहें उन्हें लिखना ठीक है!
एक कारण हो सकता है कि आप उन्हें पाने के लिए किसी वर्ग की एपीआई का दस्तावेजीकरण करना चाहें - यदि सॉफ़्टवेयर अपवाद को फेंक देता है जैसे ही कोई प्रोग्रामर इसे गलत उपयोग करने की कोशिश करता है, तो वे इसे गलत उपयोग नहीं करेंगे! उदाहरण के लिए यदि आपके पास डेटा रीडिंग प्रक्रिया के दौरान सत्यापन है, तो यह संभव नहीं है कि डेटा में घातक त्रुटियां होने पर प्रक्रिया के परिणामों को जारी रखने और उपयोग करने में सक्षम हो। इस स्थिति में, यदि आप यह सुनिश्चित करने के लिए कि कोई अन्य प्रोग्रामर इस स्थिति के लिए जाँच करता है, तो आउटपुट थ्रो प्राप्त करना चाहते हैं।
वे एक सबसिस्टम / विधि / जो कुछ भी है की मान्यताओं और सीमाओं को दस्तावेज करने का एक तरीका है। सामान्य मामले में उन्हें नहीं पकड़ा जाना चाहिए! यह इसलिए भी है क्योंकि सिस्टम में जिस तरह से एक साथ काम किया जा रहा है, वे कभी नहीं फेंकते हैं: यदि अपवाद होता है, तो यह पता चलता है कि कोड के टुकड़े की धारणाएं पूरी नहीं हुई हैं - जैसे कि यह रास्ते में दुनिया भर में इसके साथ बातचीत नहीं कर रहा है यह मूल रूप से करने का इरादा था। यदि आप एक अपवाद को पकड़ते हैं जो इस उद्देश्य के लिए लिखा गया था, तो इसका मतलब है कि सिस्टम ने अप्रत्याशित / असंगत स्थिति में प्रवेश किया है - इससे अंततः डेटा का क्रैश या भ्रष्टाचार हो सकता है या इसी तरह का पता लगाने / डिबग करने के लिए बहुत कठिन होने की संभावना है।
अपवाद संदेश रिपोर्टिंग त्रुटियों का एक बहुत ही कठिन तरीका है - उन्हें एन-मस्से एकत्र नहीं किया जा सकता है और केवल वास्तव में एक स्ट्रिंग होती है। यह उन्हें इनपुट डेटा में समस्याओं की रिपोर्ट करने के लिए अनुपयुक्त बनाता है। सामान्य रूप से सिस्टम में स्वयं को एक त्रुटि स्थिति में प्रवेश नहीं करना चाहिए। इसके परिणामस्वरूप उन संदेशों को प्रोग्रामर के लिए डिज़ाइन किया जाना चाहिए, न कि उपयोगकर्ताओं के लिए - इनपुट डेटा में गलत होने वाली चीज़ों को खोजा जा सकता है और उपयोगकर्ताओं को अधिक उपयुक्त (कस्टम) स्वरूपों में रिले किया जा सकता है।
इस नियम के अपवाद (haha!) IO जैसी चीजें हैं जहां अपवाद आपके नियंत्रण में नहीं हैं और अग्रिम रूप से जांच नहीं की जा सकती है।
यह सभी MSDN में प्रलेखित है (जैसा कि अन्य उत्तरों में जुड़ा हुआ है) लेकिन यहाँ अंगूठे का एक सामान्य नियम है ...
सेटर में, यदि आपकी संपत्ति ऊपर और उससे परे के प्रकार से मान्य होनी चाहिए। उदाहरण के लिए, PhoneNumber नामक एक प्रॉपर्टी में शायद रेगेक्स वेलिडेशन होना चाहिए और यदि फॉर्मेट मान्य नहीं है तो एक त्रुटि फेंकनी चाहिए।
प्राप्तकर्ताओं के लिए, संभवतः जब मूल्य शून्य है, लेकिन सबसे अधिक संभावना है कि कुछ ऐसा है जिसे आप कॉलिंग कोड (प्रति डिज़ाइन सुविधाओं के अनुसार) पर संभालना चाहेंगे।
MSDN: मानक अपवाद प्रकारों को पकड़ना और फेंकना
यह एक बहुत ही जटिल प्रश्न है और उत्तर इस बात पर निर्भर करता है कि आपकी वस्तु का उपयोग कैसे किया जाता है। अंगूठे के एक नियम के रूप में, संपत्ति पाने वाले और बसने वाले जो "लेट बाइंडिंग" होते हैं, उन्हें अपवादों को नहीं फेंकना चाहिए, जबकि विशेष रूप से "शुरुआती बाइंडिंग" वाले गुणों को आवश्यकता पड़ने पर अपवादों को फेंक देना चाहिए। BTW, Microsoft का कोड विश्लेषण उपकरण मेरी राय में संपत्तियों के उपयोग को बहुत कम परिभाषित कर रहा है।
"लेट बाइंडिंग" का अर्थ है कि प्रतिबिंब के माध्यम से गुण पाए जाते हैं। उदाहरण के लिए Serializeable "विशेषता का उपयोग इसके गुणों के माध्यम से किसी वस्तु को क्रमबद्ध / निष्क्रिय करने के लिए किया जाता है। इस तरह की स्थिति के दौरान एक अपवाद को फेंकना एक भयावह तरीके से चीजों को तोड़ता है और अधिक मजबूत कोड बनाने के लिए अपवादों का उपयोग करने का एक अच्छा तरीका नहीं है।
"अर्ली बाइंडिंग" का मतलब है कि एक संपत्ति का उपयोग कोड द्वारा कंपाइलर में बंधा हुआ है। उदाहरण के लिए जब कुछ कोड जिसे आप एक संपत्ति पाने वाले के संदर्भ में लिखते हैं। इस मामले में जब वे समझ में आते हैं तो अपवादों को फेंकना ठीक है।
आंतरिक विशेषताओं वाली एक वस्तु में उन विशेषताओं के मूल्यों द्वारा निर्धारित एक स्थिति होती है। गुण व्यक्त करने वाले गुण जो वस्तु की आंतरिक स्थिति के बारे में जागरूक और संवेदनशील हैं, का उपयोग देर से बंधन के लिए नहीं किया जाना चाहिए। उदाहरण के लिए, मान लें कि आपके पास एक ऑब्जेक्ट है जिसे खोला जाना चाहिए, एक्सेस किया जाना चाहिए, फिर बंद कर दिया जाना चाहिए। इस मामले में पहले बिना कॉल किए संपत्तियों तक पहुंचने के परिणामस्वरूप अपवाद होना चाहिए। मान लीजिए, इस मामले में, कि हम एक अपवाद नहीं फेंकते हैं और हम एक अपवाद को फेंकने के बिना एक मूल्य के लिए कोड एक्सेस की अनुमति देते हैं? भले ही यह एक गैर-समझदार व्यक्ति से मूल्य प्राप्त करने पर भी कोड खुश दिखाई देगा। अब हमने कोड को खराब स्थिति में डाल दिया है क्योंकि यह पता होना चाहिए कि यह देखने के लिए मान की जांच कैसे की जाए कि क्या यह गैर-समझदारी है। इसका मतलब यह है कि कोड को उस मूल्य के बारे में धारणा बनाना चाहिए जो उसे मान्य करने के लिए संपत्ति पाने वाले से मिला है। इस तरह से बुरा कोड लिखा जाता है।
मेरे पास यह कोड था जहां मैं अनिश्चित था कि किस अपवाद को फेंक दूं।
public Person
{
public string Name { get; set; }
public boolean HasPets { get; set; }
}
public void Foo(Person person)
{
if (person.Name == null) {
throw new Exception("Name of person is null.");
// I was unsure of which exception to throw here.
}
Console.WriteLine("Name is: " + person.Name);
}
मैंने मॉडल को निर्माणकर्ता में तर्क के रूप में संपत्ति को पहले स्थान पर शून्य होने से रोका।
public Person
{
public Person(string name)
{
if (name == null) {
throw new ArgumentNullException(nameof(name));
}
Name = name;
}
public string Name { get; private set; }
public boolean HasPets { get; set; }
}
public void Foo(Person person)
{
Console.WriteLine("Name is: " + person.Name);
}