2012-05-22 20 views
5

futureproof मैं Enum मूल्यों पर आधारित एक सरल स्विच बयान के साथ कुछ कोड लिख रहा हूँ। यह मेरे लिए हुआ कि भविष्य में किसी बिंदु पर एक डेवलपर एक नया मान जोड़ सकता है, इसलिए मैंने रनटाइम पर इसे कैप्चर करने और अपवाद फेंकने के लिए एक डिफ़ॉल्ट विधि शामिल की। हालांकि मुझे एहसास हुआ कि जब भी मैं इस तरह तर्क में डालता हूं, मुझे यह करना चाहिए, और मुझे लगता है कि संकलन समय के बजाए रन टाइम पर ऐसे मुद्दे ही देखेंगे। बस enum खुद के लिए टिप्पणियों को जोड़ने से परे -
मैं वहाँ कुछ कोड मैं डेवलपर है कि वे मामले कि वे enum मान अपडेट में कुछ तरीकों अद्यतन करने की आवश्यकता बताने के लिए संकलक पाने के लिए जोड़ सकते हैं यदि wonderring रहा हूँ?सी # मान्य Enum मान यह सुनिश्चित - विधि

उदा (नीचे का उदाहरण पूरी तरह से सैद्धांतिक है; मैंने विकास जीवन चक्र से स्थितियों को चुना है ताकि यह सुनिश्चित किया जा सके कि यह सबसे ज्यादा परिचित है)।

public enum DevelopmentStatusEnum 
{ 
    Development 
    //, QA //this may be added at some point in the future (or any other status could be) 
    , SIT 
    , UAT 
    , Production 
} 

    public class Example 
    { 
     public void ExampleMethod(DevelopmentStatusEnum status) 
     { 
      switch (status) 
      { 
       case DevelopmentStatusEnum.Development: DoSomething(); break; 
       case DevelopmentStatusEnum.SIT: DoSomething(); break; 
       case DevelopmentStatusEnum.UAT: DoSomething(); break; 
       case DevelopmentStatusEnum.Production: DoSomething(); break; 
       default: throw new StupidProgrammerException(); //I'd like the compiler to ensure that this line never runs, even if a programmer edits the values available to the enum, alerting the program to add a new case statement for the new enum value 
      } 
     } 
     public void DoSomething() { } 
    } 
    public class StupidProgrammerException: InvalidOperationException { } 

यह थोड़ा अकादमिक है, लेकिन मैं इसे अपने ऐप को मजबूत बनाने में उपयोगी होने के रूप में देख सकता हूं। क्या किसी ने इस पर किसी भी अच्छे विचार से पहले यह कोशिश की है कि यह कैसे हासिल किया जा सकता है?

अग्रिम धन्यवाद,

जेबी

+2

मैं वही करता हूं जो आप करते हैं। –

+2

हर बार जब आप स्वयं को एक स्विच स्टेटमेंट लिखते हैं तो आपको इसके बजाय पॉलीमोर्फिज्म का उपयोग करने में कोड को दोबारा करने पर विचार करना चाहिए। [इस अंश को देखें] (मार्टिन फाउलर की पुस्तक [रिफैक्टरिंग] (http://martinfowler.com/books/refactoring.html) के http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism)। इससे आपका कोड ओपन-क्लोज़ड प्रिंसिपल (ओसीपी) का पालन करेगा और अगले डेवलपर को स्विच स्टेटमेंट बदलने के लिए गायब होने से बचने में मदद मिलेगी। :-) –

उत्तर

11

ऐसी स्थिति में मैं सार्वजनिक स्थिर केवल पढ़ने के लिए फ़ील्ड जो वर्ग के उदाहरण हैं के साथ एक enum बल्कि एक वर्ग का उपयोग नहीं करने की कोशिश करेंगे। उदाहरण के लिए रंगों के साथ नेट फ्रेमवर्क क्या करता है देखें। एक वर्ग रंग है और आप रंगों जैसे ब्लैक, रंग, ब्लू इत्यादि का उपयोग कर सकते हैं। वे स्थिरांक नहीं हैं बल्कि लगभग सभी लाभ प्रदान करते हैं। इसके अलावा उनके पास अन्य लाभ हैं जो स्थिरांक नहीं हैं। सी # संस्करण 3 भाषा विनिर्देश देखें जो इसके बारे में भी बात करता है।

लेकिन विचार है कि आप एक मामले बयान नहीं है। आप प्रत्येक "enum" सदस्य को पर्याप्त अन्य गुण जोड़ते हैं कि विधि (कुछ या कुछ भी) ठीक से इसका इलाज कर सकती है। जब कोई अन्य डेवलपर किसी अन्य सदस्य ऑब्जेक्ट को जोड़ना चाहता है, तो उसे आवश्यक विशेषताओं की आपूर्ति करने की आवश्यकता होती है। मेरा उदाहरण: मुझे सिस्टम में सिस्टम के विभिन्न कार्यों के लिए "enum" की आवश्यकता थी। जरूरत इन कार्यों, आदि अनुमतियों के लिए जाँच की जानी लॉग इन, मैं भी माता-पिता और बच्चे के कार्यों की जरूरत है, सार कार्यों को छानने प्रयोजनों के लिए आपस में समूहित के लिए इस्तेमाल किया कार्यों, और विशेष कार्रवाई "(कुछ नाम बदलने संपादन, आदि" का हिस्सा "है) सभी "और" कोई नहीं "(कोई भी अपरिभाषित नहीं है)। प्रत्येक को डेटाबेस में एक आईडी और टेक्स्ट की भी आवश्यकता होती है। मैं चाहता था कि यह अभी भी काम करे अगर किसी ने किसी नए प्रकार की कार्रवाई का आविष्कार किया हो। मैंने जो कुछ किया वह इस तरह कुछ है (आपको बहुत कुछ कोड देने के लिए छोड़ा गया कोड):

public class Action 
    { 
    protected Action(bool Abstract, Action Parent, int ID, string Name, bool Undefined) 
    { /* snip */ } 
    protected Action(bool Abstract, Action Parent, int ID, string Name) 
     : this(Abstract, Parent, ID, Name, false) 
    { } 
    //---------------------------------------------------------------------------------------- 
    public static readonly Action All = new Action(true, null, 0, "All"); 
    public static readonly Action None = new Action(false, All, 6, "(Undefined)", true); 
    public static readonly Action Modifying = new Action(true, All, 1, "Modifying"); 
    public static readonly Action Creating = new Action(false, Modifying, 2, "Creating"); 
    public static readonly Action Deleting = new Action(false, Modifying, 3, "Deleting"); 
    public static readonly Action Editing = new Action(false, Modifying, 4, "Editing"); 
    public static readonly Action Exporting = new Action(false, All, 5, "Exporting"); 
    public static readonly Action Renaming = new Action(false, Editing, 7, "Renaming"); 
    /* snip */ 
    //---------------------------------------------------------------------------------------- 
    /* template for new entries: 
    public static readonly Action = new Action(false, All, , ""); 
    */ 
    } 

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

Log.LogAction(Action.Renaming); 

विधि LogAction उस में एक मामला बयान नहीं है। यह कार्रवाई के गुणों का उपयोग करता है।

आपकी गणना क्या है?

सम्मान

+0

मुझे यह पसंद है - सुनिश्चित नहीं है कि यह सभी उपयोग मामलों के लिए काम करेगा, लेकिन निश्चित रूप से उपयोगी है। अफसोस की बात है कि मुझे याद नहीं है कि मेरा मूल उपयोग मामला क्या था जिसने मुझे इस प्रश्न के बारे में सोचने के लिए प्रेरित किया - कई बार जब मुझे enums की आवश्यकता थी। अब मुझे इस दृष्टिकोण के बारे में पता है, जब मैं परिदृश्य की तरह एक enum के साथ प्रस्तुत करते हैं, तो इसका उपयोग करने की कोशिश करेंगे, मान लीजिए कि ऐसा करने के लिए यह समझ में आता है। एक बार फिर धन्यवाद। – JohnLBevan

+0

पीएस। इस सवाल पर किसी और का जवाब देने में पहली बार इसका इस्तेमाल किया गया - यह समाधान मेरे पिछले दृष्टिकोण से बहुत बेहतर है - धन्यवाद। http://developer42.wordpress.com/2012/10/12/path-finder-in-c/ – JohnLBevan

+1

बस एक नाइटपिकर का नोट: .NET में, आपके पास दो अलग-अलग वर्गों के साथ एक पैटर्न है, एक एकवचन (जैसे रंग या ब्रश) और एक बहुवचन, जो स्थैतिक है (रंग या ब्रश की तरह)। रंगों के लिए: http://msdn.microsoft.com/fr-fr/library/vstudio/system.windows.media.colors.black.aspx – jv42

2

मैं गलत हो सकता है, लेकिन मुझे नहीं लगता कि, संकलक इस तरह के चेतावनी प्रदान करता है। आप कुछ यूनिट परीक्षणों के साथ ऐसे मुद्दों को पकड़ सकते हैं, जो सभी संभावित एनम मानों के साथ ऊपर की तरह एक विधि का आह्वान करते हैं (इसके लिए Enum.GetValues() का उपयोग करें)। हर बार, एक डेवलपर एक enum सदस्य कहते हैं और सभी स्विच बयान, कम से कम एक इकाई परीक्षण एक "StupidProgrammerException" के साथ असफल हो जायेगी संशोधित करने के लिए भूल जाता है (Btw: मैं एक ArgumentOutOfRangeException फेंक होगा)।

+0

'InvalidEnumArgumentException' अधिक पर्याप्त होगा। –

3

मुझे सादे Enums का उपयोग करके 'समाधान' मिला है। यहाँ यह, कच्चे, हो सकता है यह एक बेहतर डिजाइन के साथ सुधार किया जा सकता है:

bool allCasesHandled; 

switch (myEnumValue) 
{ 
    case MyEnum.Value1: 
     allCasesHandled = true; 
     break; 

    //default: 
    // allCasesHandled = true; 
    // break; 
} 
System.Diagnostics.Debug.WriteLine(allCasesHandled); 

आप इस संकलन करने की कोशिश करते हैं, तो आपको एक त्रुटि 'एक अ-निरुपित चर के उपयोग' मिल जाएगा।

यह बनाए रखने के लिए थोड़ा बोझिल है, लेकिन सरल मामलों के लिए, यह उपयोगी हो सकता है, विशेष रूप से असफल होने वाली रेखा पर एक टिप्पणी के साथ।

+0

अच्छी चाल - क्योंकि डिफ़ॉल्ट रूप से एक पथ नहीं छोड़ता है जहां चर असाइनमेंट को याद किया जा सकता है । मैंने @Roelof को टिक दिया है क्योंकि मुझे लगता है कि वह समग्र रूप से सबसे अच्छा आर्किटेक्चर है, लेकिन यह बहुत अच्छा ओवरहेड के बिना जो कुछ भी आवश्यक है उसे पूरा करने के लिए यह एक अच्छा हैक है। – JohnLBevan

+0

@ जॉन एलबेवन धन्यवाद, आपका वोट समझ में आता है, यह सब कोड के दायरे पर निर्भर करता है। – jv42

0

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

संबंधित मुद्दे