2010-07-15 14 views
22

मेरे ऐप में कई अलग-अलग लुकअप मान हैं, ये मान कभी नहीं बदलते हैं, उदा। अमेरिकी राज्य उन्हें डेटाबेस टेबल में डालने की बजाय, मैं enums का उपयोग करना चाहता हूँ।एनम और प्रदर्शन

लेकिन, मुझे ऐसा करने का एहसास है कि इस तरह से कुछ enums और मेरे intums से "int" और "string" से बहुत अधिक कास्टिंग शामिल है।

वैकल्पिक, मैं किसी को लुकअप टेबल के रूप में एक शब्दकोश <> का उपयोग करके उल्लिखित किसी को देखता हूं, लेकिन enum कार्यान्वयन क्लीनर लगता है।

तो, मैं पूछना चाहूंगा कि बहुत सारे enums को चारों ओर रखते हुए और उन्हें कास्टिंग करना प्रदर्शन के लिए एक समस्या हो या मुझे लुकअप टेबल दृष्टिकोण का उपयोग करना चाहिए, जो बेहतर प्रदर्शन करता है?

संपादित करें: अन्य डेटाबेस तालिकाओं में आईडी को संग्रहीत करने के लिए कास्टिंग की आवश्यकता है।

+3

का उपयोग क्यों कर सकते हैं आपको उन्हें क्यों डालना होगा? – LukeH

+2

@LukeH: संभवत: डेटाबेस में मान केवल पूर्णांक होंगे। –

+0

@ जोन: मैंने यही अनुमान लगाया है, लेकिन ओपी से स्पष्टीकरण प्राप्त करना अच्छा होगा। – LukeH

उत्तर

29

int से एक enum में कास्ट करना बेहद सस्ता है ... यह एक शब्दकोश देखने की तुलना में तेजी हो जाएगा। असल में यह एक नो-ऑप है, बस बिट्स को एक अलग-अलग प्रकार के स्थान के साथ एक स्थान में कॉपी करना।

एक एनम मूल्य में एक स्ट्रिंग को पार्स करना कुछ हद तक धीमा होगा।

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

+0

यह एक और सवाल पूरी तरह से हो सकता है लेकिन संबंधित: अंतर्निहित 'int' मानों को मिलान करने के साथ-साथ '(int)' cast के रूप में सस्ते के साथ एक-दूसरे को enums कास्टिंग कर रहा है? –

+1

@CADBloke: मुझे उम्मीद है, हाँ। लेकिन कोशिश करें कि यह आपके लिए महत्वपूर्ण है :) –

13

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

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

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

संपादित

प्रदर्शन तर्क के बारे में: ध्यान रखें कि आप सिर्फ नहीं कर रहे हैं किसी पूर्णांक के लिए एक Enum कास्टिंग: आप यह भी कहा कि enum है, जो काफी प्रसंस्करण समय कहते हैं पर toString() चला रहे हैं। निम्न परीक्षण पर विचार करें:

const int C = 10000; 
int[] ids = new int[C]; 
string[] names = new string[C]; 
Stopwatch sw = new Stopwatch(); 
sw.Start(); 
for (int i = 0; i< C; i++) 
{ 
    var id = (i % 50) + 1; 
    names[i] = ((States)id).ToString(); 
} 
sw.Stop(); 
Console.WriteLine("Enum: " + sw.Elapsed.TotalMilliseconds); 
var namesById = Enum.GetValues(typeof(States)).Cast<States>() 
       .ToDictionary(s => (int) s, s => s.ToString()); 
sw.Restart(); 
for (int i = 0; i< C; i++) 
{ 
    var id = (i % 50) + 1; 
    names[i] = namesById[id]; 
} 
sw.Stop(); 
Console.WriteLine("Dictionary: " + sw.Elapsed.TotalMilliseconds); 

परिणाम:

Enum: 26.4875 
Dictionary: 0.7684 

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

सी # में एनम्स को मूल्यों और तारों के बीच मैपिंग प्रदान करने के लिए डिज़ाइन नहीं किया गया था। वे दृढ़ता से टाइप किए गए निरंतर मान प्रदान करने के लिए डिज़ाइन किए गए थे जिन्हें आप कोड में पास कर सकते हैं। इस के दो मुख्य फायदे हैं:

  1. आप एक अतिरिक्त संकलक जाँच मदद से आप गलत क्रम में तर्क गुजर से बचने के सुराग है, आदि
  2. बजाय डाल "जादुई" संख्या मान (उदाहरण के लिए "42 ") अपने कोड में, आप" स्टेट्स.ऑक्लाहोमा "कह सकते हैं, जो आपके कोड को अधिक पठनीय प्रस्तुत करता है।

जावा के विपरीत, सी # स्वचालित रूप से डाली मूल्यों सुनिश्चित करें कि वे वैध (myState = (States)321) कर रहे हैं की जाँच नहीं करता है, तो आप उन्हें मैन्युअल कर बिना आदानों पर किसी भी क्रम डेटा चेकों नहीं मिलता है। यदि आपके पास कोड नहीं है जो राज्यों को स्पष्ट रूप से संदर्भित करता है ("स्टेट्स.ऑक्लाहोमा"), तो आपको ऊपर # 2 से कोई मूल्य नहीं मिलता है। यह हमें enums का उपयोग करने के लिए एकमात्र वास्तविक कारण के रूप में # 1 के साथ छोड़ देता है। यदि यह आपके लिए पर्याप्त कारण है, तो मैं आपके प्रमुख मानों के रूप में की बजाय enms का उपयोग करने का सुझाव दूंगा। फिर, जब आपको किसी स्ट्रिंग या राज्य से संबंधित कुछ अन्य मूल्य की आवश्यकता होती है, तो एक शब्दकोश लुकअप करें।

यहाँ कैसे मैं यह कर करेंगे:

public enum StateKey{ 
    AL = 1,AK,AS,AZ,AR,CA,CO,CT,DE,DC,FM,FL,GA,GU, 
    HI,ID,IL,IN,IA,KS,KY,LA,ME,MH,MD,MA,MI,MN,MS, 
    MO,MT,NE,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PW, 
    PA,PR,RI,SC,SD,TN,TX,UT,VT,VI,VA,WA,WV,WI,WY, 
} 

public class State 
{ 
    public StateKey Key {get;set;} 
    public int IntKey {get {return (int)Key;}} 
    public string PostalAbbreviation {get;set;} 

} 

public interface IStateRepository 
{ 
    State GetByKey(StateKey key); 
} 

public class StateRepository : IStateRepository 
{ 
    private static Dictionary<StateKey, State> _statesByKey; 
    static StateRepository() 
    { 
     _statesByKey = Enum.GetValues(typeof(StateKey)) 
     .Cast<StateKey>() 
     .ToDictionary(k => k, k => new State {Key = k, PostalAbbreviation = k.ToString()}); 
    } 
    public State GetByKey(StateKey key) 
    { 
     return _statesByKey[key]; 
    } 
} 

public class Foo 
{ 
    IStateRepository _repository; 
    // Dependency Injection makes this class unit-testable 
    public Foo(IStateRepository repository) 
    { 
     _repository = repository; 
    } 
    // If you haven't learned the wonders of DI, do this: 
    public Foo() 
    { 
     _repository = new StateRepository(); 
    } 

    public void DoSomethingWithAState(StateKey key) 
    { 
     Console.WriteLine(_repository.GetByKey(key).PostalAbbreviation); 
    } 
} 

इस तरह:

  1. अपने चारों ओर दृढ़ता से टाइप मूल्यों है कि एक राज्य का प्रतिनिधित्व पारित करने के लिए मिलता है,
  2. अपने देखने fail- हो जाता है तेजी से व्यवहार अगर इसे अमान्य इनपुट दिया जाता है,
  3. आप आसानी से बदल सकते हैं कि वास्तविक स्थिति डेटा भविष्य में रहता है,
  4. आप भविष्य में राज्य से संबंधित डेटा को आसानी से जोड़ सकते हैं,
  5. आप आसानी से नए राज्य, क्षेत्र, जिलों, प्रांतों, या भविष्य में जो कुछ भी जोड़ सकते हैं।
  6. एक int से नाम प्राप्त करने के बारे में Enum.ToString() का उपयोग करते समय लगभग 1512 तेज है।

[घुरघुराना]

+1

+1, मैं पूरी तरह से "पूरी तरह से अपरिवर्तनीय" भाग से सहमत नहीं हूं। यदि आप अपने दस साल का आवेदन अतीत से राजनीतिक मॉडल पर आधारित हैं तो आप इससे नफरत करेंगे और आपको अब इसके लिए समर्थन नहीं मिलता है ... –

+1

असहमत है कि इसमें कोई बड़ा प्रदर्शन अंतर नहीं है; सी # में enums सिर्फ ints हैं, तो यह उनके और ints के बीच कास्ट करने के लिए बहुत तेज है। आपके अंक अच्छे हैं, लेकिन संभावित रूप से अनावश्यक लचीलापन के लिए प्रदर्शन बलिदान की सिफारिश करने के लिए मुझे कड़ी मेहनत की जाएगी। – TMN

+2

@ टीएमएन: यहां तक ​​कि यदि enums तेजी से होगा, हम इस तरह की उच्च गति के बारे में बात कर रहे हैं कि यह विशाल बहुमत में उल्लेखनीय नहीं होगा। प्रदर्शन में एक मामूली सुधार के लिए लचीलापन बलिदान की सिफारिश करने के लिए मुझे कठोर दबाव डाला जाएगा। हालांकि, जैसा कि यह पता चला है, एक शब्दकोश लुकअप वास्तव में उस चीज के लिए बहुत तेज होगा जो वह करने के बारे में बात कर रहा है। मेरा अद्यतन उत्तर देखें। – StriplingWarrior

0

Enums लगभग कुछ भी, विशेष रूप से शब्दकोश की तुलना में काफी बेहतर प्रदर्शन करेगा। Enums केवल एक बाइट का उपयोग करें। लेकिन आप कास्टिंग क्यों करेंगे? ऐसा लगता है कि आपको हर जगह enums का उपयोग करना चाहिए।

+5

एन्म्स आमतौर पर 4 बाइट्स का उपयोग करेंगे - उनके अंतर्निहित प्रकार 'int' तक डिफ़ॉल्ट होते हैं जबतक कि आप स्पष्ट रूप से अन्यथा घोषित नहीं करते हैं। – LukeH

+1

"बहुत अधिक प्रदर्शन" भाग बड़े पैमाने पर इस बात पर निर्भर करता है कि आप इसे प्राप्त करने के बाद enum के साथ क्या कर रहे हैं। यदि आप इसे स्विच स्टेटमेंट में उपयोग करते हैं, तो एनम तेजी से होंगे। यदि आप उस पर ToString को कॉल करते हैं, तो पूर्व-जनसंख्या वाला शब्दकोश तेज़ होगा। मेरा जवाब देखें – StriplingWarrior

-2

enum से बचें जैसा कि आप कर सकते हैं: enums को बेस क्लास से प्राप्त सिंगलटन को प्रतिस्थापित किया जाना चाहिए या इंटरफेस को कार्यान्वित करना चाहिए।

enum का प्रचलन सी

के एक पुराने शैली प्रोग्रामिंग

आप अमेरिका स्टेट्स के लिए एक enum उपयोग करने के लिए है, तो आप निवासियों की संख्या, कैपिटल ... जरूरत है, और आप शुरू से आता है इन सभी इंफोस को पाने के लिए बहुत सारे स्विच की आवश्यकता होगी।

+0

सी # में Enums वस्तुओं नहीं हैं। वे वास्तव में बेस क्लास से प्राप्त नहीं होते हैं या इंटरफेस को लागू नहीं करते हैं। वे सिर्फ प्रकार-सुरक्षित स्थिरांक हैं। जब वे इस तरह इस्तेमाल होते हैं तो वे उपयोगी हो सकते हैं, लेकिन अगर गलत समझा जाता है तो वे खतरनाक होते हैं। – StriplingWarrior

+0

मुझे पता है कि enums वस्तु नहीं हैं। यही कारण है कि मैं कहता हूं कि वे बेकार हैं। वैसे भी मैंने अपना जवाब साफ़ कर दिया। – onof

2

आप TypeSafeEnum रों

यहाँ एक आधार वर्ग यहाँ है इस्तेमाल कर सकते हैं

Public MustInherit Class AbstractTypeSafeEnum 
    Private Shared ReadOnly syncroot As New Object 
    Private Shared masterValue As Integer = 0 

    Protected ReadOnly _name As String 
    Protected ReadOnly _value As Integer 

    Protected Sub New(ByVal name As String) 
     Me._name = name 
     SyncLock syncroot 
      masterValue += 1 
      Me._value = masterValue 
     End SyncLock 
    End Sub 

    Public ReadOnly Property value() As Integer 
     Get 
      Return _value 
     End Get 
    End Property 

    Public Overrides Function ToString() As String 
     Return _name 
    End Function 

    Public Shared Operator =(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean 
     Return (ats1._value = ats2._value) And Type.Equals(ats1.GetType, ats2.GetType) 
    End Operator 

    Public Shared Operator <>(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean 
     Return Not (ats1 = ats2) 
    End Operator 

End Class 

और एक Enum:

Public NotInheritable Class EnumProcType 
    Inherits AbstractTypeSafeEnum 

    Public Shared ReadOnly CREATE As New EnumProcType("Création") 
    Public Shared ReadOnly MODIF As New EnumProcType("Modification") 
    Public Shared ReadOnly DELETE As New EnumProcType("Suppression") 

    Private Sub New(ByVal name As String) 
     MyBase.New(name) 
    End Sub 

End Class 

और यह अंतर्राष्ट्रीयकरण जोड़ना आसान हो जाता है।

इस तथ्य के बारे में खेद है कि यह वीबी और फ्रेंच में है।

चीयर्स!

+0

क्योंकि डेटाबेस में पूर्णांक मान मैप किए जाते हैं, इसलिए स्पष्ट int मान निर्दिष्ट करना संभव होगा, इसलिए यदि वे पुन: व्यवस्थित होते हैं तो वे नहीं बदलते हैं। – StriplingWarrior

+0

अच्छा, मुझे लगता है कि कोड को बदलने के लिए कोड को बदलने में बहुत मुश्किल नहीं होगी। –

0

वैकल्पिक रूप से आप स्थिरांक

+0

स्थिरांक का उपयोग कैसे फायदेमंद होगा? – StriplingWarrior

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