TL; DR बहुत नीचे तक स्क्रॉल करें।
मैं जो देख रहा हूं, आप C # के शीर्ष पर एक नई भाषा लागू कर रहे हैं। एनम एक पहचानकर्ता के प्रकार को निरूपित करने के लिए लगता है (या, कुछ भी जिसका नाम है और जो नई भाषा के स्रोत कोड में प्रकट होता है), जो नोड्स पर लागू होता है जो प्रोग्राम के ट्री प्रतिनिधित्व में जोड़े जाते हैं।
इस विशेष स्थिति में, विभिन्न प्रकार के नोड्स के बीच बहुत कम बहुरूपी व्यवहार होते हैं। दूसरे शब्दों में, जबकि पेड़ के लिए बहुत अलग प्रकार (नोड्स) के नोड्स को सक्षम करने के लिए आवश्यक है, इन नोड्स की वास्तविक यात्रा मूल रूप से एक विशाल अगर-फिर-चेन (या instanceof
/ is
चेक) का सहारा लेगी । ये विशाल जाँच संभवत: परियोजना के कई अलग-अलग स्थानों पर होगी। यही कारण है कि एनम मददगार लग सकते हैं, या, वे कम से कम instanceof
/ is
चेक के रूप में सहायक होते हैं ।
विज़िटर पैटर्न अभी भी उपयोगी हो सकता है। दूसरे शब्दों में, विभिन्न कोडिंग शैलियाँ हैं जिनका उपयोग विशालकाय श्रृंखला के बजाय किया जा सकता है instanceof
। हालाँकि, यदि आप विभिन्न लाभों और कमियों पर चर्चा चाहते हैं, तो आपने instanceof
एनम के बारे में समझाने के बजाय परियोजना की सबसे खराब श्रृंखला से एक कोड उदाहरण प्रदर्शित करने के लिए चुना होगा ।
यह वर्गों और विरासत पदानुक्रम उपयोगी नहीं हैं कहने के लिए नहीं है। काफी विपरीत। जबकि कोई भी बहुरूपतापूर्ण व्यवहार नहीं है जो हर घोषणा प्रकार पर काम करता है (इस तथ्य से अलग कि प्रत्येक घोषणा में एक Name
संपत्ति होनी चाहिए ), पास के भाई-बहनों द्वारा साझा किए गए प्रचुर मात्रा में बहुरंगी व्यवहार हैं। उदाहरण के लिए, Function
और Procedure
शायद कुछ व्यवहारों को साझा करें (दोनों टाइप करने योग्य हैं और टाइप किए गए इनपुट तर्कों की एक सूची को स्वीकार करते हैं), और PropertyGet
निश्चित रूप से Function
(दोनों वाले ReturnType
) से व्यवहार का वारिस होगा । आप या तो विशाल या तो-और-श्रृंखला के लिए इनमेट्स या इनहेरिटेंस चेक का उपयोग कर सकते हैं, लेकिन बहुरंगी व्यवहार, हालांकि खंडित, अभी भी कक्षाओं में लागू किया जाना चाहिए।
instanceof
/ is
चेक के अति प्रयोग के खिलाफ कई ऑनलाइन सलाह हैं । प्रदर्शन इसका एक कारण नहीं है। बल्कि, इसका कारण प्रोग्रामर को व्यवस्थित रूप से उपयुक्त बहुरूपी व्यवहार की खोज करने से रोकना है, जैसे कि instanceof
/ is
एक बैसाखी है। लेकिन आपकी स्थिति में, आपके पास कोई अन्य विकल्प नहीं है, क्योंकि ये नोड्स बहुत कम हैं।
अब यहां कुछ ठोस सुझाव दिए गए हैं।
गैर-पत्ती समूहों का प्रतिनिधित्व करने के कई तरीके हैं।
अपने मूल कोड के निम्नलिखित अंश की तुलना करें ...
[Flags]
public enum DeclarationType
{
Member = 1 << 7,
Procedure = 1 << 8 | Member,
Function = 1 << 9 | Member,
Property = 1 << 10 | Member,
PropertyGet = 1 << 11 | Property | Function,
PropertyLet = 1 << 12 | Property | Procedure,
PropertySet = 1 << 13 | Property | Procedure,
LibraryFunction = 1 << 23 | Function,
LibraryProcedure = 1 << 24 | Procedure,
}
इस संशोधित संस्करण में:
[Flags]
public enum DeclarationType
{
Nothing = 0, // to facilitate bit testing
// Let's assume Member is not a concrete thing,
// which means it doesn't need its own bit
/* Member = 1 << 7, */
// Procedure and Function are concrete things; meanwhile
// they can still have sub-types.
Procedure = 1 << 8,
Function = 1 << 9,
Property = 1 << 10,
PropertyGet = 1 << 11,
PropertyLet = 1 << 12,
PropertySet = 1 << 13,
LibraryFunction = 1 << 23,
LibraryProcedure = 1 << 24,
// new
Procedures = Procedure | PropertyLet | PropertySet | LibraryProcedure,
Functions = Function | PropertyGet | LibraryFunction,
Properties = PropertyGet | PropertyLet | PropertySet,
Members = Procedures | Functions | Properties,
LibraryMembers = LibraryFunction | LibraryProcedure
}
यह संशोधित संस्करण गैर-ठोस घोषणा प्रकारों की ओर बिट्स आवंटित करने से बचता है। इसके बजाय, गैर-ठोस घोषणा प्रकार (घोषणा प्रकारों के सार समूह) में बस सभी बच्चों के बीच बिट-या-बिट्स (बिट्स का संघ) मान होता है।
एक चेतावनी है: यदि एक सार घोषणा प्रकार है जिसमें एक ही बच्चा है, और अगर ठोस एक (बच्चे) से सार एक (माता-पिता) के बीच अंतर करने की आवश्यकता है, तो सार एक को अभी भी अपने स्वयं के बिट की आवश्यकता होगी ।
एक प्रश्न जो इस प्रश्न के लिए विशिष्ट है: एक Property
शुरू में एक पहचानकर्ता है (जब आप केवल उसका नाम देखते हैं, बिना यह देखे कि कोड में इसका उपयोग कैसे किया जाता है), लेकिन यह जैसे ही आप देखते हैं कि यह कैसे उपयोग किया जा रहा है PropertyGet
/ PropertyLet
/ PropertySet
कोड में। दूसरे शब्दों में, पार्सिंग के विभिन्न चरणों में, आपको या तो एक Property
पहचानकर्ता को चिह्नित करने की आवश्यकता हो सकती है क्योंकि "यह नाम एक संपत्ति को संदर्भित करता है", और बाद में इसे "कोड की यह रेखा एक निश्चित तरीके से इस संपत्ति तक पहुंच रही है"।
इस चेतावनी को हल करने के लिए, आपको दो सेटों की आवश्यकता हो सकती है; एक enum दर्शाता है कि एक नाम (पहचानकर्ता) क्या है; एक और एनम निरूपित करता है कि कोड क्या करने की कोशिश कर रहा है (जैसे कि किसी चीज़ को शरीर घोषित करना, किसी चीज़ को किसी निश्चित तरीके से उपयोग करने की कोशिश करना)।
इस बात पर विचार करें कि क्या प्रत्येक एनीम मूल्य के बारे में सहायक जानकारी को इसके बजाय किसी सरणी से पढ़ा जा सकता है।
यह सुझाव अन्य सुझावों के साथ पारस्परिक रूप से अनन्य है क्योंकि इसके लिए छोटे गैर-नकारात्मक पूर्णांक मानों में दो-दो मान परिवर्तित करने की आवश्यकता होती है।
public enum DeclarationType
{
Procedure = 8,
Function = 9,
Property = 10,
PropertyGet = 11,
PropertyLet = 12,
PropertySet = 13,
LibraryFunction = 23,
LibraryProcedure = 24,
}
static readonly bool[] DeclarationTypeIsMember = new bool[32]
{
?, ?, ?, ?, ?, ?, ?, ?, // bit[0] ... bit[7]
true, true, true, true, true, true, ?, ?, // bit[8] ... bit[15]
?, ?, ?, ?, ?, ?, ?, true, // bit[16] ... bit[23]
true, ... // bit[24] ...
}
static bool IsMember(DeclarationType dt)
{
int intValue = (int)dt;
return (intValue < 0 || intValue >= 32) ? false : DeclarationTypeIsMember[intValue];
// you can also throw an exception if the enum is outside range.
}
// likewise for IsFunction(dt), IsProcedure(dt), IsProperty(dt), ...
स्थिरता समस्याग्रस्त होने वाली है।
जांचें कि क्या सी # प्रकार (एक वंशानुक्रम पदानुक्रम में कक्षाएं) और आपके एनम मूल्यों के बीच एक-से-एक मानचित्रण है।
(वैकल्पिक रूप से, आप प्रकारों के साथ एक-से-एक मैपिंग सुनिश्चित करने के लिए अपने enum मानों को ट्विक कर सकते हैं।)
सी # में, बहुत सारे पुस्तकालय Type object.GetType()
अच्छे या बुरे के लिए निफ्टी विधि का दुरुपयोग करते हैं ।
कहीं भी आप एक मूल्य के रूप में एनम का भंडारण कर रहे हैं, आप अपने आप से पूछ सकते हैं कि क्या आप Type
इसके बजाय एक मूल्य के रूप में संग्रहीत कर सकते हैं ।
इस ट्रिक का उपयोग करने के लिए, आप दो रीड-ओनली हैश टेबल को इनिशियलाइज़ कर सकते हैं, अर्थात्:
// For disambiguation, I'll assume that the actual
// (behavior-implementing) classes are under the
// "Lang" namespace.
static readonly Dictionary<Type, DeclarationType> TypeToDeclEnum = ...
{
{ typeof(Lang.Procedure), DeclarationType.Procedure },
{ typeof(Lang.Function), DeclarationType.Function },
{ typeof(Lang.Property), DeclarationType.Property },
...
};
static readonly Dictionary<DeclarationType, Type> DeclEnumToType = ...
{
// same as the first dictionary;
// just swap the key and the value
...
};
वर्ग और विरासत पदानुक्रम का सुझाव देने वालों के लिए अंतिम संकेत ...
एक बार जब आप देख सकते हैं कि एनमेज वंशानुक्रम पदानुक्रम के लिए एक सन्निकटन हैं , तो निम्नलिखित सलाह है:
- अपने वंशानुक्रम पदानुक्रम को पहले डिजाइन (या सुधार),
- फिर वापस जाओ और अपने वंश को उस वंशानुक्रम पदानुक्रम को अनुमानित करने के लिए डिज़ाइन करें।
DeclarationType
। अगर मैं यह निर्धारित करना चाहता हूं कि क्याx
इसका कोई उपप्रकार है या नहींy
, तो मैं शायद यह लिखना चाहता हूं कि जैसा हैx.IsSubtypeOf(y)
, वैसा नहींx && y == y
।