विरासत के माध्यम से एक दुश्मनी का विस्तार


85

मुझे पता है कि यह एनमों के विचार के खिलाफ है, लेकिन क्या सी # / जावा में एनमों का विस्तार करना संभव है? मेरा मतलब है कि "विस्तार" दोनों को एक एनम में नए मूल्यों को जोड़ने के अर्थ में, लेकिन मौजूदा एयूएम से विरासत में मिलने वाले ओओ अर्थ में भी।

मुझे लगता है कि यह जावा में संभव नहीं है, क्योंकि यह केवल उन्हें हाल ही में मिला है (जावा 5?)। C # लोगों को अधिक क्षमा करने वाला लगता है जो पागल चीजें करना चाहते हैं, हालांकि, इसलिए मैंने सोचा कि यह किसी तरह संभव हो सकता है। संभवतः इसे प्रतिबिंब के माध्यम से हैक किया जा सकता है (यह नहीं कि आप वास्तव में उस पद्धति का उपयोग करेंगे)?

मैं किसी भी दिए गए तरीके को लागू करने के लिए जरूरी नहीं हूं, यह सिर्फ मेरी जिज्ञासा को उकसाता है जब यह मेरे साथ हुआ है :-)


क्या इससे आपके सवाल का जवाब मिलता है?
एनम

जवाबों:


103

Enums का विस्तार आप नहीं कर सकते इसका कारण यह है कि यह बहुरूपता के साथ समस्याओं को जन्म देगा।

मान लें कि आपके पास ए, बी, और सी के साथ एक एन्युम मायनम है, और इसे वैल्यू डी के साथ मायएक्स्टीनम के रूप में विस्तारित करें।

मान लीजिए कि एक विधि एक पैरामीटर के रूप में उदाहरण के लिए, कहीं मायनम मान की अपेक्षा करती है। यह एक MyExtEnum मान की आपूर्ति करने के लिए कानूनी होना चाहिए, क्योंकि यह एक उपप्रकार है, लेकिन अब जब आप मूल्य डी है, तो आप क्या करने जा रहे हैं?

इस समस्या को खत्म करने के लिए, enums का विस्तार करना अवैध है


4
दरअसल, इसका कारण यह है कि इसका कोई मतलब नहीं है। आप जिस समस्या का उल्लेख करते हैं, अर्थात क्लाइंट कोड जो इसे प्राप्त करने की अपेक्षा करता है, वह अभी भी वर्तमान कार्यान्वयन के साथ मौजूद नहीं है - वास्तव में कंपाइलर आपको switchएक defaultमामला प्रदान किए बिना या अपवाद को फेंकने के बिना एनम मूल्यों पर चलने नहीं देता । और, भले ही यह किया गया हो, रनटाइम पर एनम एक अलग संकलन से आ सकता है
रैफेल

@ राफेल मैंने अभी यह कोशिश की, और कम से कम जावा 7 में, आप एक defaultमामले या फेंकने के बिना एनम पर स्विच कर सकते हैं ।
दत्त

@ दथन आप निश्चित रूप से सही हैं! जैसा कि यह लिखा है, कि बस गलत है - शायद मुझे इसे हटा देना चाहिए? मैं इस मामले के बारे में सोच रहा था जब आप switchएक आवश्यक मूल्य प्रदान करने के लिए उपयोग करते हैं, जैसे कि एक स्थानीय का प्रारंभिक, याreturn
राफेल

3
यह व्यक्तिगत नहीं है, रिक। लेकिन यह बहुत ज्यादा सबसे खराब कारण है! बहुरूपता और enum ...DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);
बिटरबेल्यू

41

जब बिल्ट-इन एनम पर्याप्त नहीं होते हैं, तो आप इसे पुराने तरीके से कर सकते हैं और अपना खुद का शिल्प कर सकते हैं। उदाहरण के लिए, यदि आप एक अतिरिक्त संपत्ति जोड़ना चाहते हैं, उदाहरण के लिए, एक विवरण क्षेत्र, आप इसे निम्नानुसार कर सकते हैं:

public class Action {
    public string Name {get; private set;}
    public string Description {get; private set;}

    private Action(string name, string description) {
        Name = name;
        Description = description;
    }

    public static Action DoIt = new Action("Do it", "This does things");
    public static Action StopIt = new Action("Stop It", "This stops things");
}

फिर आप इसे एनम की तरह मान सकते हैं:

public void ProcessAction(Action a) {
    Console.WriteLine("Performing action: " + a.Name)
    if (a == Action.DoIt) {
       // ... and so on
    }
}

चाल यह सुनिश्चित करने के लिए है कि कंस्ट्रक्टर निजी है (या यदि आप वारिस करना चाहते हैं तो संरक्षित है), और यह कि आपके इंस्टेंस स्थिर हैं।


मैं एक C # व्यक्ति नहीं हूं, लेकिन क्या आप अंतिम (या सील / कास्ट / जो भी हो) का एक सा नहीं चाहते हैं?
टॉम हैटिन -

1
मैं ऐसा नहीं मानता। या, कम से कम, उस स्थिति के लिए नहीं जहां आप इस वर्ग से नए "एनम" मान जोड़ना चाहते हैं। अंतिम और मुहरबंद विरासत IIRC को रोकें।
alastairs

4
@alastairs मुझे लगता है कि वह जोड़ने का मतलब finalकरने के लिए public static Action DoIt = new Action("Do it", "This does things");लाइन, बल्कि वर्ग की तुलना में।
क्रश करें

1
जैसा कि जोड़कर readonly, public static readonly Action DoIt = new Action("Do it", "This does things");
आल्हा

40

आप गलत तरीके से जा रहे हैं: किसी एनम के उपवर्ग में कम प्रविष्टियाँ होंगी ।

स्यूडोकोड में, सोचें:

enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat };  // (not valid C#)

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

लेकिन नहीं, C # / Java उप-एनम, AFAICT की अनुमति नहीं देते हैं, हालांकि यह कई बार उपयोगी होगा। यह शायद इसलिए है क्योंकि उन्होंने इंटमेड प्रतीकों (जैसे लिस्प) के बजाय एनमों को (जैसे सी) लागू करने के लिए चुना। (ऊपर, क्या करता है (पशु) 1 प्रतिनिधित्व करता है, और क्या (स्तनपायी) 1 प्रतिनिधित्व करता है, और क्या वे एक ही मूल्य हैं?)

आप अपनी खुद की एनम-लाइक क्लास (एक अलग नाम के साथ) लिख सकते हैं, जो इसे प्रदान करता है, हालाँकि। सी # विशेषताओं के साथ यह भी अच्छा लग सकता है।


3
दिलचस्प विश्लेषण। इस तरह कभी नहीं सोचा था!
16

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

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

@Kieveli मान लीजिए कि आपके पास 'स्ट्रीमवटर' क्लास था (स्ट्रीम लेता है - स्ट्रीम लिखता है)। आप 'TextWriter: StreamWriter' बनाएंगे (स्ट्रीम लेते हैं - टेक्स्ट लिखते हैं)। अब आप 'HtmlWriter: TextWriter' बनाते हैं (स्ट्रीम लेते हैं - सुंदर html लिखते हैं)। अब HtmlWriter में स्पष्ट रूप से अधिक सदस्य, विधियाँ वगैरह हैं। अब साउंड कार्ड से एक स्ट्रीम लेने की कोशिश करें और इसे HtmlWriter का उपयोग करके फाइल करने के लिए लिखें :)
बेदखल करना

यह उदाहरण वंचित है, और यह साबित नहीं करता है कि विस्तारित वर्ग में कभी भी अधिक मान नहीं होना चाहिए। enum VehicalParts {लाइसेंस, गति, क्षमता}; एनम कारपार्ट्स {स्टीयरिंगव्हेल, विनशिल्ड}; + सब कुछ जो वाहन के पास भी है
बर्नौली छिपकली

12

एनमों को सभी संभावित मूल्यों की गणना का प्रतिनिधित्व करने के लिए माना जाता है, इसलिए इसका विस्तार विचार के विपरीत होता है।

हालाँकि, आप जावा में क्या कर सकते हैं (और संभवतः C ++ 0x) में एक एनम वर्ग के बजाय एक इंटरफ़ेस है। फिर आपको मानक मानों को एक ऐसे एनम में रखें जो सुविधा को लागू करता है। जाहिर है आप java.util.EnumSet और इस तरह का उपयोग करने के लिए नहीं मिलता है। यह "अधिक एनआईओ सुविधाओं" में लिया गया दृष्टिकोण है, जो कि जेडीके 7 में होना चाहिए।

public interface Result {
    String name();
    String toString();
}
public enum StandardResults implements Result {
    TRUE, FALSE
}


public enum WTFResults implements Result {
    FILE_NOT_FOUND
}

4

आप रन-टाइम पर एक मौजूदा एनम से लेबल और मानों को पुनः प्राप्त करने के लिए .NET प्रतिबिंब का उपयोग कर सकते हैं ( Enum.GetNames()और Enum.GetValues()वे दो विशिष्ट तरीके हैं जो आप उपयोग करेंगे) और फिर उन तत्वों के साथ एक नया बनाने के लिए कोड इंजेक्शन का उपयोग करें और कुछ नए भी। ऐसा लगता है कि कुछ हद तक "मौजूदा एनम से विरासत में मिला है"।


2

अगर आप स्रोत कोड पर वापस जाते हैं और किसी अन्य तरीके (विरासत या प्रतिबिंब, यदि या तो संभव है) को वापस लाने और पुस्तकालय के उन्नयन के बाद आपको हिट करने की संभावना है, तो enums जोड़ना एक सामान्य बात है। उन्होंने एक ही एनुम नाम या समान एनम मान पेश किया है - मैंने बहुत सारे लोवेल कोड देखे हैं जहां पूर्णांक संख्या बाइनरी एन्कोडिंग से मेल खाती है, जहां आप समस्याओं में भाग लेंगे

आदर्श रूप से कोड रेफ़रिंग एनम को केवल (या स्विच) के बराबर लिखा जाना चाहिए, और एनम सेट होने की उम्मीद न करके भविष्य के प्रमाण होने की कोशिश करें


2

अगर आपका मतलब बेस क्लास सेंस में है, तो जावा में ... नहीं।

लेकिन अगर आप का मतलब है कि आप गुणों और विधियों के लिए एक एनम मूल्य का विस्तार कर सकते हैं।

उदाहरण के लिए, निम्नलिखित एक ब्रैकेट का उपयोग करता है:

class Person {
    enum Bracket {
        Low(0, 12000),
        Middle(12000, 60000),
        Upper(60000, 100000);

        private final int low;
        private final int high;
        Brackets(int low, int high) {
            this.low = low;
            this.high = high;
        }

        public int getLow() {
            return low;
        }

        public int getHigh() {
            return high;
        }

        public boolean isWithin(int value) {
           return value >= low && value <= high;
        }

        public String toString() {
            return "Bracket " + low + " to " + high;
        }
    }

    private Bracket bracket;
    private String name;

    public Person(String name, Bracket bracket) {
        this.bracket = bracket;
        this.name = name;
    }

    public String toString() {
        return name + " in " + bracket;
    }        
}

यह .NET में मान प्रकार (संरचना) की तरह लगता है। मुझे नहीं पता था कि आप जावा में ऐसा कर सकते हैं।
alastairs

2

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

एक और कठिनाई यदि आप भाषा डिजाइनर थे, तो आप मूल्यों की कार्यक्षमता () पद्धति को कैसे संरक्षित कर सकते हैं, जो सभी मानों को वापस करने के लिए माना जाता है। आप इस पर क्या लागू करेंगे और यह सभी मूल्यों को कैसे एकत्रित करेगा?




0

हम्म - जहां तक ​​मुझे पता है, यह नहीं किया जा सकता है - एन्यूमरेशन डिजाइन-टाइम पर लिखे गए हैं और प्रोग्रामर की सुविधा के रूप में उपयोग किए जाते हैं।

मुझे पूरा यकीन है कि जब कोड संकलित किया जाता है, तो आपकी गणना में नामों के लिए समकक्ष मान प्रतिस्थापित किए जाएंगे, जिससे एक गणना की अवधारणा को हटा दिया जाता है और (इसलिए) इसे विस्तारित करने की क्षमता होती है।


0

मैं C # गणनाओं में उन मूल्यों को जोड़ना चाहूंगा जो मौजूदा मूल्यों के संयोजन हैं। उदाहरण के लिए (यह वही है जो मैं करना चाहता हूं):

AnchorStyles के रूप में परिभाषित किया गया है

public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }

और मैं एक AnchorStyles.BottomRight = राइट + बॉटम जोड़ना चाहूंगा बजाय कहने के

my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;

मैं बस कह सकता हूं

my_ctrl.Anchor = AnchorStyles.BottomRight;

यह ऊपर बताई गई किसी भी समस्या का कारण नहीं है, इसलिए यह संभव हो तो अच्छा होगा।


0

कुछ समय पहले भी मैंने ऐसा कुछ करना चाहा था और पाया था कि एनम एक्सटेंशन बहुत सारी बुनियादी अवधारणाओं को आत्मसात करेंगे ... (सिर्फ बहुरूपता नहीं)

लेकिन फिर भी यू करने की आवश्यकता हो सकती है यदि एनम बाहरी पुस्तकालय में घोषित किया गया है और याद रखें कि इस एनम का उपयोग करते समय आपको एक विशेष सावधानी बरतनी चाहिए:

public enum MyEnum { A = 1, B = 2, C = 4 }

public const MyEnum D = (MyEnum)(8);
public const MyEnum E = (MyEnum)(16);

func1{
    MyEnum EnumValue = D;

    switch (EnumValue){
      case D:  break;
      case E:  break;
      case MyEnum.A:  break;
      case MyEnum.B:  break;
   }
}

0

जहां तक ​​जावा का सवाल है, इसकी अनुमति नहीं है क्योंकि एक एनम में तत्वों को जोड़ने से प्रभावी रूप से एक उप वर्ग के बजाय एक सुपर क्लास बन जाएगा।

विचार करें:

 enum Person (JOHN SAM}   
 enum Student extends Person {HARVEY ROSS}

बहुरूपता का एक सामान्य उपयोग मामला होगा

 Person person = Student.ROSS;   //not legal

जो स्पष्ट रूप से गलत है।


0

एक अस्थायी / स्थानीय वर्कअराउंड , जब आप बस बहुत स्थानीय / एक बार उपयोग करना चाहते हैं:

enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat,  MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal(   (Animals)xyz   );

सभी उत्तर यहाँ देखें: Enum "वंशानुक्रम"

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.