अपवाद फेंकें या कोड को विफल करें


52

मुझे आश्चर्य हो रहा है कि क्या इस शैली के खिलाफ कोई पेशेवरों और विपक्ष हैं:

private void LoadMaterial(string name)
{
    if (_Materials.ContainsKey(name))
    {
        throw new ArgumentException("The material named " + name + " has already been loaded.");
    }

    _Materials.Add(
        name,
        Resources.Load(string.Format("Materials/{0}", name)) as Material
    );
}

यह विधि, प्रत्येक के लिए name, केवल एक बार चलाई जानी चाहिए । _Materials.Add()एक अपवाद को फेंक देगा अगर इसे उसी के लिए कई बार कहा जाएगा name। क्या मेरा गार्ड, परिणामस्वरूप, पूरी तरह से बेमानी है, या कुछ कम स्पष्ट लाभ हैं?

अगर किसी को दिलचस्पी है, तो वह C #, एकता है।


3
यदि आप किसी सामग्री को बिना गार्ड के दो बार लोड करते हैं तो क्या होगा? क्या _Materials.Addएक अपवाद फेंकता है?
user253751

2
वास्तव में मैंने पहले ही एक अपवाद का उल्लेख किया है: P
async

9
साइड नोट्स: 1) string.Formatअपवाद संदेश के निर्माण के लिए स्ट्रिंग समाकलन का उपयोग करने पर विचार करें । 2) केवल तभी उपयोग करें asजब आप उम्मीद करते हैं कि कलाकार विफल होंगे और परिणाम की जांच करेंगे null। यदि आप हमेशा ए पाने की उम्मीद करते हैं Material, तो कलाकारों का उपयोग करें (Material)Resources.Load(...)। एक स्पष्ट कास्ट अपवाद एक शून्य संदर्भ अपवाद से डिबग करना आसान है जो बाद में होता है।
कोडइन्चोस

3
इस विशिष्ट मामले में, आपके कॉल करने वालों को एक साथी मिल सकता है LoadMaterialIfNotLoadedया ReloadMaterial(यह नाम सुधार का उपयोग कर सकता है) विधि उपयोगी है।
jpmc26

1
किसी अन्य नोट पर: यह पैटर्न किसी सूची में आइटम जोड़ने के लिए ठीक है। हालाँकि पूरी सूची भरने के लिए इस पैटर्न का उपयोग न करें क्योंकि आप O (n ^ 2) स्थिति में चलेंगे जहाँ बड़ी सूचियों के साथ आप प्रदर्शन के मुद्दों में भाग लेंगे। आप इसे 100 प्रविष्टियों पर ध्यान नहीं देंगे, लेकिन 1000 प्रविष्टियों पर निश्चित रूप से और 10.000 प्रविष्टियों पर यह एक बड़ी अड़चन होगी।
Pieter B

जवाबों:


109

लाभ यह है कि आपके "कस्टम" अपवाद में एक त्रुटि संदेश है जो इस फ़ंक्शन को कॉल करने वाले किसी भी व्यक्ति के लिए सार्थक है बिना यह जाने कि यह कैसे लागू किया गया है (जो भविष्य में आप हो सकता है!)।

दी गई, इस मामले में वे शायद अनुमान लगा पाएंगे कि "मानक" अपवाद का क्या मतलब है, लेकिन आप अभी भी यह स्पष्ट कर रहे हैं कि उन्होंने आपके अनुबंध में उल्लंघन किया, बजाय आपके कोड में कुछ अजीब बग के।


3
इस बात से सहमत। किसी पूर्व शर्त उल्लंघन के अपवाद को फेंकना लगभग हमेशा बेहतर होता है।
फ्रैंक हिलमैन

22
"लाभ यह है कि आपके" कस्टम "अपवाद में एक त्रुटि संदेश है जो इस फ़ंक्शन को कॉल करने वाले किसी भी व्यक्ति के लिए सार्थक है बिना यह जाने कि यह कैसे लागू किया गया है (जो भविष्य में आप हो सकता है!)।" शीर्ष सलाह।
async

2
"स्पष्ट रूप से निहितार्थ से बेहतर है।" - पायथन का ज़ेन
jpmc26

4
भले ही आपके द्वारा डाली गई _Materials.Addत्रुटि कॉलर को प्रेषित करने की त्रुटि नहीं है, लेकिन मुझे लगता है कि त्रुटि को पुन: प्रकाशित करने का यह तरीका अक्षम है। हर के लिए सफल की कॉल LoadMaterial(सामान्य ऑपरेशन) आप एक ही विवेक परीक्षण किया जाएगा है दो बार , में LoadMaterialमें फिर से और फिर _Materials.Add। यदि अधिक परतें लपेटी जाती हैं, तो प्रत्येक एक ही शैली को नियोजित करता है, तो आप एक ही परीक्षण के कई गुना अधिक हो सकते हैं।
मार्क वैन लीउवेन

15
... इसके बजाय में जल्दी से आगे बढ़नेवाला पर विचार _Materials.Addबिना शर्त, तो पकड़ने के लिए एक संभावित त्रुटि और हैंडलर में एक अलग से एक फेंक देते हैं। अतिरिक्त काम अब केवल गलत मामलों में किया जाता है, असाधारण निष्पादन पथ जहां आप वास्तव में दक्षता के बारे में चिंता नहीं करते हैं।
मार्क वैन लीउवेन

100

मैं Ixrec के जवाब से सहमत हूं । हालांकि, आप एक तीसरे विकल्प पर विचार करना चाह सकते हैं: फ़ंक्शन को बेकार बनाना। दूसरे शब्दों में, एक फेंकने के बजाय जल्दी लौटें ArgumentException। यह अक्सर बेहतर होता है यदि आप अन्यथा यह जांचने के लिए मजबूर होंगे कि क्या यह LoadMaterialहर बार कॉल करने से पहले ही लोड हो चुका है । आपके पास कम पूर्व शर्त, प्रोग्रामर पर कम संज्ञानात्मक भार है।

एक अपवाद को फेंकना बेहतर होगा यदि यह वास्तव में एक प्रोग्रामर की गलती है, जहां यह स्पष्ट होना चाहिए और संकलन समय पर जाना जाना चाहिए यदि सामग्री पहले से लोड की गई है, बिना कॉल करने से पहले रनटाइम पर जांच करने के लिए।


2
दूसरी ओर, एक समारोह में चुपचाप विफल होने के कारण अप्रत्याशित व्यवहार हो सकता है जिसके परिणामस्वरूप बाद में बग को खोजने में मुश्किल होती है।
फिलिप

30
@Philipp फ़ंक्शन चुपचाप विफल नहीं होगा। बेरोजगार होने का मतलब है कि इसे कई बार चलाने का एक ही प्रभाव है जैसा कि इसे एक बार चलाना। दूसरे शब्दों में, यदि सामग्री पहले से ही भरी हुई है, तो हमारी कल्पना ("सामग्री लोड होनी चाहिए") पहले से ही संतुष्ट है, इसलिए हमें कुछ भी करने की आवश्यकता नहीं है। हम अभी लौट सकते हैं।
वारबो

8
मुझे यह अधिक पसंद है, वास्तव में। बेशक, अनुप्रयोगों की आवश्यकताओं द्वारा दी गई बाधाओं के आधार पर, यह गलत हो सकता है। तो फिर, मैं सुखद तरीकों का एक परम प्रशंसक हूं।
एफपी

6
@ झिलमिल अगर हम इसके बारे में सोचते हैं, तो LoadMaterialनिम्नलिखित बाधाएं हैं: "इसे कॉल करने के बाद सामग्री हमेशा भरी हुई है और लोड की गई सामग्री की संख्या में कमी नहीं हुई है"। एक तीसरे बाधा "सामग्री को दो बार नहीं जोड़ा जा सकता है" के लिए एक अपवाद को फेंकना मुझे मूर्खतापूर्ण और उल्टा लगता है। फ़ंक्शन को बेकार बनाने से निष्पादन आदेश और एप्लिकेशन स्थिति पर कोड की निर्भरता कम हो जाती है। यह मेरे लिए दोहरी जीत जैसा लगता है।
बेंजामिन ग्रुएनबाम

7
मैं इस विचार को पसंद करता हूं, लेकिन एक मामूली बदलाव का सुझाव देता हूं: एक बुलियन लौटाएं जो यह दर्शाता है कि कुछ भी लोड किया गया था। यदि कॉलर वास्तव में एप्लिकेशन लॉजिक के बारे में परवाह करता है, तो वे उसकी जांच कर सकते हैं और एक अपवाद फेंक सकते हैं।
user949300

8

आपको जो मूल प्रश्न पूछना है, वह यह है: आप अपने फ़ंक्शन के लिए इंटरफ़ेस क्या चाहते हैं? विशेष रूप से, क्या हालत _Materials.ContainsKey(name)फ़ंक्शन का एक पूर्व शर्त है?

यदि यह एक पूर्व शर्त नहीं है, तो फ़ंक्शन को सभी संभावित घाटों के लिए एक अच्छी तरह से परिभाषित परिणाम प्रदान करना होगा name। इस मामले में, अपवाद को फेंक दिया जाता है अगर फ़ंक्शन के इंटरफ़ेस का हिस्सा nameनहीं _Materialsबनता है। इसका मतलब है कि इसे इंटरफ़ेस प्रलेखन का हिस्सा होना चाहिए और यदि आप कभी भी भविष्य में उस अपवाद को बदलने का निर्णय लेते हैं, तो यह एक ब्रेकिंग इंटरफ़ेस परिवर्तन होगा

अधिक दिलचस्प सवाल यह है कि क्या होता है अगर यह एक पूर्व शर्त है। उस स्थिति में पूर्व शर्त स्वयं फ़ंक्शन इंटरफ़ेस का हिस्सा बन जाती है, लेकिन जिस तरह से एक फ़ंक्शन व्यवहार करता है जब इस स्थिति का उल्लंघन किया जाता है, तो यह आवश्यक रूप से इंटरफ़ेस का हिस्सा नहीं है।

इस मामले में, आपने जो दृष्टिकोण पोस्ट किया है, वह पूर्व शर्त उल्लंघन की जाँच कर रहा है और त्रुटि की रिपोर्ट कर रहा है, जिसे रक्षात्मक प्रोग्रामिंग के रूप में जाना जाता है । रक्षात्मक प्रोग्रामिंग इस बात में अच्छी है कि यह उपयोगकर्ता को जल्दी सूचित करता है जब उन्होंने गलती की और फर्जी तर्क के साथ फ़ंक्शन को कॉल किया। यह बुरा है कि यह रखरखाव के बोझ को काफी बढ़ाता है, क्योंकि उपयोगकर्ता कोड यह निर्भर कर सकता है कि फ़ंक्शन एक निश्चित तरीके से पूर्व शर्त उल्लंघन को संभालता है। विशेष रूप से, यदि आप पाते हैं कि रनटाइम चेक भविष्य में एक प्रदर्शन अड़चन बन जाता है (इस तरह के एक साधारण मामले की संभावना नहीं है, लेकिन अधिक जटिल पूर्व शर्त के लिए काफी आम है), तो आप अब इसे हटाने में सक्षम नहीं हो सकते हैं।

यह पता चला है कि उन नुकसान बहुत महत्वपूर्ण हो सकते हैं, जिन्होंने कुछ मंडलियों में रक्षात्मक प्रोग्रामिंग तरह की खराब प्रतिष्ठा दी। हालांकि, प्रारंभिक लक्ष्य अभी भी मान्य है: हम अपने फ़ंक्शन के उपयोगकर्ताओं को नोटिस करना चाहते हैं जब उन्होंने गलती की थी।

इसलिए कई डेवलपर्स आजकल इन प्रकार के मुद्दों के लिए थोड़ा अलग दृष्टिकोण प्रस्तावित करते हैं। एक अपवाद को फेंकने के बजाय, वे पूर्व शर्त की जाँच के लिए एक मुखर-जैसे तंत्र का उपयोग करते हैं। यह है कि, पूर्वगामी डिबग बिल्डों में उपयोगकर्ताओं को जल्दी गलतियों को पकड़ने में सहायता करने के लिए जाँच कर सकते हैं, लेकिन वे फ़ंक्शन इंटरफ़ेस का हिस्सा नहीं हैं। अंतर पहली नज़र में सूक्ष्म लग सकता है, लेकिन यह अभ्यास में भारी अंतर ला सकता है।

तकनीकी रूप से, उल्लंघन वाले पूर्व शर्त के साथ एक फ़ंक्शन को कॉल करना अपरिभाषित व्यवहार है। लेकिन कार्यान्वयन उन मामलों का पता लगाने और उपयोगकर्ता को तुरंत सूचित करने का निर्णय ले सकता है यदि ऐसा होता है। अपवाद दुर्भाग्य से इसे लागू करने के लिए एक अच्छा उपकरण नहीं है, क्योंकि उपयोगकर्ता कोड उन पर प्रतिक्रिया कर सकता है और इस प्रकार उनकी उपस्थिति पर भरोसा करना शुरू कर सकता है।

क्लासिक रक्षात्मक दृष्टिकोण के साथ समस्याओं की एक विस्तृत व्याख्या के लिए, साथ ही मुखर -शैली पूर्व शर्त जांच के लिए एक संभावित कार्यान्वयन, जॉन लेकोस की चर्चा डिफेंसिव प्रोग्रामिंग डन राइट से कैप्पन 2014 ( स्लाइड्स , वीडियो )।


4

यहाँ पहले से ही कुछ उत्तर दिए गए हैं, लेकिन यहाँ का उत्तर Unity3D को ध्यान में रखता है (यह उत्तर Unity3D के लिए बहुत विशिष्ट है, मैं इसे सबसे अलग संदर्भों में सबसे अलग करूँगा):

सामान्य तौर पर, Unity3D पारंपरिक रूप से अपवादों का उपयोग नहीं करता है। यदि आप Unity3D में एक अपवाद को फेंक देते हैं, तो यह आपके औसत .NET एप्लिकेशन की तरह कुछ भी नहीं है, अर्थात् यह कार्यक्रम को रोक नहीं पाएगा, सबसे अधिक आप संपादक को पॉज़ करने के लिए कॉन्फ़िगर कर सकते हैं। यह सिर्फ लॉग इन होगा। यह आसानी से गेम को अमान्य स्थिति में डाल सकता है और एक कैस्केड प्रभाव पैदा कर सकता है जो त्रुटियों को ट्रैक करने में मुश्किल बनाता है। तो मैं एकता के मामले में कहूंगा, Addअपवाद को फेंकना एक विशेष रूप से अवांछनीय विकल्प है।

लेकिन अपवादों की गति की जांच करने पर कुछ मामलों में समय से पहले अनुकूलन का मामला नहीं है क्योंकि मोनो कुछ प्लेटफार्मों पर एकता में कैसे काम करता है। वास्तव में, iOS पर Unity3D कुछ उन्नत स्क्रिप्ट अनुकूलन का समर्थन करता है, और अक्षम अपवाद * उनमें से एक का एक साइड इफेक्ट है। यह वास्तव में विचार करने के लिए कुछ है क्योंकि उन ऑप्टिमाइज़ेशन ने कई उपयोगकर्ताओं के लिए बहुत मूल्यवान साबित किया है, जो कि यूनिटी 3 डी में अपवादों के उपयोग को सीमित करने पर विचार करने के लिए एक यथार्थवादी मामला दिखा रहा है। (* इंजन से अपवाद प्रबंधित, आपका कोड नहीं)

मैं कहूंगा कि एकता में आप एक अधिक विशिष्ट दृष्टिकोण लेना चाहते हैं। विडंबना यह है कि इसे लिखने के समय बहुत ही कम जवाब दिया गया , एक तरीका दिखाता है कि मैं विशेष रूप से यूनिटी 3 डी के संदर्भ में कुछ इस तरह से लागू कर सकता हूं (कहीं और ऐसा ही कुछ वास्तव में अस्वीकार्य है, और यहां तक ​​कि एकता में यह काफी अयोग्य है)।

एक अन्य दृष्टिकोण जिस पर मैं विचार करूंगा, वह वास्तव में एक त्रुटि का संकेत नहीं है, क्योंकि कॉलर चिंतित है, बल्कि Debug.LogXXकार्यों का उपयोग कर रहा है। इस तरह आपको एक अनछुए अपवाद को फेंकने के समान व्यवहार मिलता है (क्योंकि यूनिटी 3 डी उन्हें कैसे संभालती है) बिना किसी जोखिम के रेखा के नीचे एक अजीब स्थिति में डालकर। यह भी विचार करें कि क्या यह वास्तव में एक त्रुटि है (क्या आपके मामले में एक ही सामग्री को दो बार जरूरी लोड करने की कोशिश की जा रही है? या यह ऐसा मामला हो सकता है जहां Debug.LogWarningअधिक लागू होता है)।

और Debug.LogXXअपवादों के बजाय फ़ंक्शंस जैसी उपयोग की जाने वाली चीज़ों के संबंध में , आपको अभी भी विचार करना होगा कि क्या होता है जब कोई अपवाद उस चीज़ से फेंका जाएगा जो एक मान लौटाता है (जैसे गेटमेटेरिट)। मैं त्रुटि को लॉग करने के साथ-साथ अशक्त होकर ( फिर से, केवल एकता में ) यह दृष्टिकोण करने के लिए जाता हूं । मैं तब अपने मोनोबोहेवियर्स में अशक्त जांच का उपयोग करता हूं ताकि यह सुनिश्चित हो सके कि सामग्री जैसी कोई निर्भरता शून्य मूल्य नहीं है, और यदि यह है तो मोनोबोएवियर को अक्षम करें। एक सरल व्यवहार के लिए एक उदाहरण जिसके लिए कुछ निर्भरता की आवश्यकता होती है वह कुछ इस तरह है:

    public void Awake()
    {
        _inputParameters = GetComponent<VehicleInputParameters>();
        _rigidbody = GetComponent<Rigidbody>();
        _rigidbodyTransform = _rigidbody.transform;
        _raycastStrategySelector = GetComponent<RaycastStrategySelectionBehavior>();

        _trackParameters =
            SceneManager.InstanceOf.CurrentSceneData.GetValue<TrackParameters>();

        this.DisableIfNull(() => _rigidbody);
        this.DisableIfNull(() => _raycastStrategySelector);
        this.DisableIfNull(() => _inputParameters);
        this.DisableIfNull(() => _trackParameters);
    }

SceneData.GetValue<>यह आपके उदाहरण के समान है कि यह एक शब्दकोश पर एक फ़ंक्शन को कॉल करता है जो एक अपवाद को फेंकता है। लेकिन एक अपवाद को फेंकने के बजाय यह उपयोग करता है Debug.LogErrorजो एक सामान्य अपवाद की तरह एक स्टैक ट्रेस देता है और अशक्त देता है। जो चेक * फॉलो करते हैं वे व्यवहार को अमान्य स्थिति में मौजूद रहने देने के बजाय अक्षम कर देंगे।

* चेक इस तरह दिखते हैं कि एक छोटे सहायक की वजह से मैं उस फॉर्मैट संदेश को प्रिंट करता हूं जब यह गेम ऑब्जेक्ट को निष्क्रिय करता है **। ifयहाँ काम के साथ सरल अशक्त चेक (** सहायक के चेक केवल डिबग बिल्ड (जोर की तरह) में संकलित किए जाते हैं। लंबोदा और इस तरह अभिव्यक्ति का उपयोग करना एकता में प्रदर्शन पर टोल ले सकता है)


1
कुछ सही नई जानकारी को ढेर में जोड़ने के लिए +1। मुझे इसकी उम्मीद नहीं थी।
Ixrec

3

मुझे दो मुख्य उत्तर पसंद हैं, लेकिन यह सुझाव देना चाहता हूं कि आपके फ़ंक्शन नामों में सुधार किया जा सकता है। मैं जावा का उपयोग कर रहा हूं, इसलिए YMMV, लेकिन एक "ऐड" विधि चाहिए, IMO, एक अपवाद को फेंक न दें यदि आइटम पहले से ही वहां है। यह आइटम को फिर से जोड़ना चाहिए , या, यदि गंतव्य एक सेट है, तो कुछ भी न करें। चूंकि वह सामग्री का व्यवहार नहीं है। इसके लिए, जिसे ट्रायप्यूट या AddOnce या AddOrThrow या समान नाम दिया जाना चाहिए।

इसी तरह, आपके LoadMaterial का नाम बदलकर LoadIfAbsent या Put या TryLoad या LoadOrThrow होना चाहिए (इस पर निर्भर करते हुए कि आप उत्तर # 1 या # 2 का उपयोग करते हैं) या कुछ ऐसे।

C # एकता नामकरण सम्मेलनों का पालन करें जो भी वे हैं।

यह विशेष रूप से उपयोगी होगा यदि आपके पास अन्य AddFoo और LoadBar फ़ंक्शन हैं जहां एक ही चीज़ को दो बार लोड करने की अनुमति है। स्पष्ट नामों के बिना डेवलपर्स निराश हो जाएंगे।


एक अंतर betweeen C # Dictionary.Add () शब्दार्थ है (देखें msdn.microsoft.com/en-us/library/k7z0zy8k%28v=vs.110%29.aspx ) और जावा संग्रह .add () शब्दार्थ (देखें डॉक्स)। oracle.com/javase/8/docs/api/java/util/… )। C # रिटर्न शून्य है और अपवाद को फेंकता है। जबकि, जावा बूल वापस करता है और पहले से संग्रहीत मूल्य को नए मूल्य के साथ बदल देता है या जब नया तत्व जोड़ा नहीं जा सकता है तो एक अपवाद फेंकता है।
कैस्पर वैन डेन बर्ग

कैस्पर - धन्यवाद, और दिलचस्प। आप C # शब्दकोश में एक मूल्य कैसे प्रतिस्थापित करते हैं? (जावा पुट के बराबर) ()। उस पेज पर बिल्ट इन मेथड न देखें।
user949300

अच्छा सवाल, कोई भी Dictionary.Remove () कर सकता है (देखें msdn.microsoft.com/en-us/library/bb356469%28v=vs.110%29.aspx ) उसके बाद एक Dictionary.Add () ( msdn.microsoft देखें) .com / en-us / पुस्तकालय / bb338565% 28v = vs.110% 29.aspx ), लेकिन यह थोड़ा अजीब लगता है।
कैस्पर वैन डेन बर्ग

@ user949300 डिक्शनरी [कुंजी] = मान प्रविष्टि को प्रतिस्थापित करता है यदि यह पहले से मौजूद है
रुपे

@ रुपे और शायद कुछ फेंकता है अगर यह नहीं करता है। सब मुझे बहुत अजीब लगता है। अधिकांश dict की स्थापना ग्राहकों परवाह नहीं है wheteher एक प्रविष्टि था वहाँ, वे सिर्फ परवाह है कि, उनके सेटअप कोड के बाद, यह है वहाँ। जावा कलेक्शंस एपीआई (IMHO) के लिए एक स्कोर करें। PHP डक्ट्स के साथ भी अजीब है, यह उस मिसाल का पालन करने के लिए एक गलती थी।
user949300

3

सभी उत्तर बहुमूल्य विचारों को जोड़ते हैं, मैं उन्हें संयोजित करना चाहूंगा:

LoadMaterial()ऑपरेशन के इच्छित और अपेक्षित शब्दार्थ पर निर्णय लें । कम से कम निम्नलिखित विकल्प मौजूद हैं:

  • nameलोडेडमैटर्स पर एक पूर्व शर्त : →

    जब पूर्व शर्त का उल्लंघन किया जाता है, तो इसका प्रभाव LoadMaterial()अनिर्दिष्ट होता है (जैसा कि कॉमिकसैंस द्वारा जवाब दिया गया है )। यह कार्यान्वयन और भविष्य के परिवर्तनों में सबसे अधिक स्वतंत्रता देता है । या,LoadMaterial()

  • बुला के प्रभाव LoadMaterial(name)के साथ nameLoadedMaterials निर्दिष्ट कर रहे हैं; या तो:

शब्दार्थ पर निर्णय लेते समय, आपको एक कार्यान्वयन चुनना होगा। निम्नलिखित विकल्प और विचार जहां प्रस्तावित हैं:

  • (के रूप में एक कस्टम अपवाद फेंक सुझाव दिया द्वारा Ixrec ) →

    लाभ यह है कि आपके "कस्टम" अपवाद में एक त्रुटि संदेश है जो इस फ़ंक्शन को कॉल करने वाले किसी भी व्यक्ति के लिए सार्थक है - Ixrec और User16547

    • बार-बार जाँच की लागत से बचने के लिए nameed LoadedMaterials आप मार्क वैन लीउवेन की सलाह का पालन ​​कर सकते हैं :

      ... इसके बजाय _Materials.Add में बेरोकटोक विचार करें, फिर एक संभावित त्रुटि को पकड़ें और हैंडलर में एक अलग फेंक दें।

  • चलो Dictionay.Add अपवाद फेंक →

    अपवाद फेंकने वाला कोड बेमानी है। - जॉन रेन्नोर

    हालांकि, अधिकांश मतदाता Ixrec से अधिक सहमत हैं

    इस कार्यान्वयन को चुनने का अतिरिक्त कारण हैं:

    • कि कॉलर पहले से ही ArgumentExceptionअपवादों को संभाल सकते हैं, और
    • स्टैक जानकारी खोने से बचने के लिए।

    लेकिन अगर ये दो कारण महत्वपूर्ण हैं, तो आप अपने कस्टम अपवाद को भी प्राप्त कर सकते हैं ArgumentExceptionऔर मूल का उपयोग जंजीर अपवाद के रूप में कर सकते हैं।

  • कार्ल Bielefeldt द्वारा anwser केLoadMaterial() रूप में बेरोजगार बनाएं और सबसे अधिक बार (75 बार) उत्थान किया।

    इस व्यवहार के कार्यान्वयन विकल्प:

    • Dictionary.ContainsKey () के साथ जांचें

    • हमेशा फोन Dictionary.Add () को पकड़ने ArgumentExceptionफेंक देता है जब कुंजी पहले से मौजूद डालने और उस अपवाद की अनदेखी करने के। दस्तावेज़ कि अपवाद की अनदेखी आप क्या करने के लिए और क्यों करने का इरादा है।

      • जब LoadMaterials()(लगभग) हमेशा प्रत्येक के लिए एक बार कॉल किया जाता है name, तो यह बार-बार nameM लोडेडमैटेरियल्स सीएफ की जाँच करने से बचता हैमार्क वैन लीउवेन । हालाँकि,
      • जब LoadedMaterials()अक्सर एक ही के लिए कई बार कहा जाता है name, तो यह ArgumentExceptionऔर स्टैक अनइंडिंग को फेंकने का महंगा (महंगा) खर्च होता है।
    • मैंने सोचा था कि ट्राईगेट () में एक TryAdd-मेथोड एनालॉग मौजूद है, जो आपको डिक्शनरी में अनपेक्षित कॉल के महंगे अपवाद को फेंकने और ढेर लगाने से बचने की अनुमति देगा।

      लेकिन यह TryAdd-मिथोड मौजूद नहीं है।


1
सबसे व्यापक उत्तर होने के लिए +1। यह संभवतः ओपी के बाद मूल रूप से बहुत आगे निकल गया है, लेकिन यह सभी विकल्पों का एक उपयोगी सारांश है।
इक्सेरेक

1

अपवाद फेंकने का कोड बेमानी है।

यदि आप फोन करते हैं:

सामग्री के लिए सामग्री

उसी कुंजी के साथ यह एक फेंक देगा

System.ArgumentException

संदेश होगा: "उसी कुंजी के साथ एक आइटम पहले ही जोड़ा जा चुका है।"

ContainsKeyजांच अनावश्यक के बाद से अनिवार्य रूप से समान व्यवहार इसके बिना प्राप्त किया जाता है। एकमात्र आइटम जो अलग है वह अपवाद में वास्तविक संदेश है। यदि कस्टम त्रुटि संदेश होने से सच्चा लाभ है, तो गार्ड कोड में कुछ योग्यता है।

अन्यथा, मैं शायद इस मामले में गार्ड को बाहर कर दूंगा।


0

मुझे लगता है कि यह कोडिंग कन्वेंशन प्रश्न की तुलना में एपीआई डिजाइन के बारे में अधिक प्रश्न है।

कॉल करने का अपेक्षित परिणाम (अनुबंध) क्या है:

LoadMaterial("wood");

यदि कॉलर उम्मीद कर सकता है / गारंटी दी जाती है कि इस पद्धति को कॉल करने के बाद, सामग्री "लकड़ी" भरी हुई है, तो मुझे कोई अपवाद नहीं दिखाई देता है जब उस सामग्री को पहले से लोड किया गया हो।

यदि सामग्री लोड करते समय कोई त्रुटि होती है, उदाहरण के लिए, डेटाबेस कनेक्शन नहीं खोला जा सकता है, या रिपॉजिटरी में कोई सामग्री "लकड़ी" नहीं है, तो उस समस्या के कॉलर को सूचित करने के लिए अपवाद फेंकना सही है।


-2

अगर यह सही है तो विधि को न बदलें, तो यह सही है और अगर यह नहीं था तो यह 'गलत' है?

private bool LoadMaterial(string name)
{
   if (_Materials.ContainsKey(name))

    {

        return false; //already present
    }

    _Materials.Add(
        name,
        Resources.Load(string.Format("Materials/{0}", name)) as Material
    );

    return true;

}

15
जो कार्य त्रुटि मान लौटाते हैं, वे बिल्कुल प्रतिमान हैं, जिन्हें अपवाद अप्रचलित माना जाता है।
फिलीपिंस

क्या यह मामला है? मुझे लगा कि यह केवल semipredicate के साथ मामला था ( en.wikipedia.org/wiki/Semipredicate_problem ) क्योंकि ओपी कोड नमूने में, सिस्टम में एक सामग्री जोड़ने में विफल कोई वास्तविक समस्या नहीं है। विधि का उद्देश्य यह सुनिश्चित करना है कि सामग्री सिस्टम में है जब आप इसे चलाते हैं, और यह वही है जो यह विधि करता है। (यहां तक ​​कि अगर यह विफल रहता है) रिटर्निंग बूलियन केवल इंगित करता है कि क्या विधि ने पहले से ही इस मामले को जोड़ने की कोशिश की है या नहीं। ps: मैं इस बात पर ध्यान नहीं देता कि एक ही नाम के साथ कई मामले हो सकते हैं।
MrIveck

1
मुझे लगता है कि मैंने स्वयं इसका हल ढूंढ लिया: en.wikipedia.org/wiki/… यह बताता है कि Ixrec का उत्तर सबसे सही है
MrIveck

@Philipp मामले में कोडर / युक्ति ने निर्णय लिया है कि जब आप दो बार लोड करने का प्रयास करते हैं तो कोई त्रुटि नहीं होती है । वापसी मूल्य, इस अर्थ में, त्रुटि मूल्य नहीं है, बल्कि एक सूचना है।
user949300
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.