कोड में डेटा संग्रहीत करना


17

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

public class Country
{
    public string Code { get; set; }
    public string EnglishName {get;set;}
}

public static class CountryHelper
{
    public static List<Country> Countries = new List<Country>
        {
            new Country {Code = "AU", EnglishName = "Australia"},
            ...
            new Country {Code = "SE", EnglishName = "Sweden"},
            ...
        };

    public static Country GetByCode(string code)
    {
        return Countries.Single(c => c.Code == code);
    }
}

मैं अतीत में ऐसा करने से दूर हो गया हूं क्योंकि डेटा सेट अपेक्षाकृत छोटे थे और ऑब्जेक्ट बहुत सरल थे। अब मैं ऐसी चीज़ के साथ काम कर रहा हूं जिसमें अधिक जटिल वस्तुएं होंगी (5 - 10 गुण प्रत्येक, कुछ गुण शब्दकोशों में) और कुल 200 वस्तुएं।

डेटा अपने आप बहुत कम बदलता है और जब यह बदलता है तो यह वास्तव में उतना महत्वपूर्ण भी नहीं होता है। इसलिए इसे अगले रिलीज संस्करण में रोल करना पूरी तरह से ठीक है।

मैं अपने डेटा स्रोत को असेंबली में संग्रहीत करने के लिए T4 या ERB या किसी अन्य अस्थायी समाधान का उपयोग करने की योजना बना रहा हूं।

ऐसा लगता है कि मेरे विकल्प हैं

  1. XML में डेटा स्टोर करें। असेंबली संसाधन के रूप में XML फ़ाइल संकलित करें। आवश्यकतानुसार डेटा लोड करें, रिपीट-यूज़ प्रदर्शन के लिए लोड डेटा को एक शब्दकोश में स्टोर करें।
  2. किसी प्रकार की स्थैतिक वस्तु या ऐसी वस्तुएं उत्पन्न करें जो स्टार्टअप पर आरंभिक हों।

मुझे पूरा यकीन है कि मैं विकल्प 1 के प्रदर्शन निहितार्थ को समझता हूं। कम से कम, मेरा कूबड़ यह है कि इसमें तारकीय प्रदर्शन नहीं होगा।

विकल्प 2 के लिए, मुझे नहीं पता कि क्या करना है। मैं वास्तव में इस डेटा को C # कोड में संग्रहीत करने और इसे प्रारंभ करने के सर्वोत्तम तरीकों को जानने के लिए .NET फ्रेमवर्क के आंतरिक के बारे में पर्याप्त नहीं जानता। मैं कैसे System.Globalization.CultureInfo.GetCulture(name)काम करता है यह देखने के लिए .NET रिफ्लेक्टर का उपयोग करने के बारे में सोच रहा था , क्योंकि यह वास्तव में मैं क्या चाहता हूं के लिए एक बहुत ही समान वर्कफ़्लो है। दुर्भाग्य से यह निशान एक पर समाप्त हो गया extern, इसलिए वहां कोई संकेत नहीं है। क्या सभी आंकड़ों के साथ एक स्थिर संपत्ति को शुरू करना, जैसा कि मेरे उदाहरण में, जाने का तरीका है? या वस्तुओं को मांग पर बनाना और फिर उन्हें इस तरह कैश करना बेहतर होगा?

    private static readonly Dictionary<string, Country> Cache = new Dictionary<string,Country>(); 

    public static Country GetByCode(string code)
    {
        if (!Cache.ContainsKey(code))
            return Cache[code];

        return (Cache[code] = CreateCountry(code));
    }

    internal static Country CreateCountry(string code)
    {
        if (code == "AU")
            return new Country {Code = "AU", EnglishName = "Australia"};
        ...
        if (code == "SE")
            return new Country {Code = "SE", EnglishName = "Sweden"};
        ...
        throw new CountryNotFoundException();
    }

एक स्थिर सदस्य में एक बार उन्हें बनाने का लाभ यह है कि आप सभी वस्तुओं को देखने के लिए LINQ या जो कुछ भी उपयोग कर सकते हैं और यदि आप चाहें तो उन्हें क्वेरी कर सकते हैं। हालांकि मुझे संदेह है कि ऐसा करने से स्टार्टअप परफॉर्मेंस पेनल्टी लगती है। मुझे उम्मीद है कि किसी को इसके साथ अनुभव होगा और अपनी राय साझा कर सकता है!


5
200 वस्तुओं? मुझे नहीं लगता कि आपको प्रदर्शन के बारे में चिंता करना होगा, खासकर अगर यह एक बार की लागत है।
22

1
आपके पास एक और विकल्प है, जो वस्तुओं को कोड में संग्रहीत करना है, फिर सामान्य के रूप में निर्भरता इंजेक्शन के माध्यम से एक संदर्भ पास करें। इस प्रकार, यदि आप बदलना चाहते हैं कि उनका निर्माण कैसे किया जाता है, तो आपके पास हर जगह से सीधे उनके पास इंगित करने वाले स्थिर संदर्भ नहीं हैं।
एमी ब्लैंकेनशिप

@ शविक: यह सच है। मैं शायद प्रदर्शन को लेकर अत्यधिक सतर्क हूं।
मूरच

@AmyBlankenship मैं हमेशा हेल्पर के तरीकों का इस्तेमाल करूँगा, लेकिन DI एक अच्छा विचार है। मैंने इसके बारे में नहीं सोचा था। मैं देता हूँ कि एक जाना और देखो अगर मुझे पैटर्न पसंद है। धन्यवाद!
मूरच

" डेटा ही बहुत मुश्किल से ही बदल जाता है और यह वास्तव में है जब यह परिवर्तन करता है महत्वपूर्ण है कि यहां तक कि नहीं। " Bosnians, सर्ब्स, क्रोट्स, Ukranians, दक्षिण Sudanis, पूर्व दक्षिण यमन, पूर्व सोवियत संघ, करने के लिए कि बताओ एट अल। यह बताएं कि हर प्रोग्रामर को जो यूरो मुद्रा में संक्रमण से निपटना था, या उन प्रोग्रामरों के लिए, जिन्हें ग्रीस के संभावित निकास से निपटना पड़ सकता है। डेटा संरचनाओं में डेटा होता है। XML फाइलें अच्छी तरह से काम करती हैं, और इन्हें आसानी से बदला जा सकता है। Ditto SQL डेटाबेस।
रॉस पैटरसन

जवाबों:


11

मैं एक विकल्प के साथ जाना होगा। यह सरल और पढ़ने में आसान है। आपके कोड को देखने वाला कोई और इसे सीधे समझ जाएगा। जरूरत पड़ने पर अपने XML डेटा को अपडेट करना भी आसान होगा। (इसके अलावा आप उपयोगकर्ता को अपडेट कर सकते हैं यदि आपके पास एक अच्छा फ्रंट एंड है और फ़ाइलों को अलग से संग्रहीत किया गया है)

यदि आपको इसकी आवश्यकता है तो केवल इसका अनुकूलन करें - समय से पहले अनुकूलन बुराई है :)


3
यदि आप C # लिख रहे हैं, तो आप एक ऐसे प्लेटफ़ॉर्म पर चल रहे हैं, जो छोटे XMLs को तेज़ प्रकाश में पार्स कर सकता है। तो यह प्रदर्शन के मुद्दों के बारे में परेशान करने लायक नहीं है।
जेम्स एंडरसन

7

यह देखते हुए कि ये अनिवार्य रूप से की-वैल्यू पेयर हैं, मैं इन स्ट्रिंग्स को संकलित समय पर आपके असेंबली में एम्बेडेड संसाधन फ़ाइल के रूप में संग्रहीत करने की सलाह देता हूं । फिर आप उन्हें पढ़कर ए का उपयोग कर सकते हैं ResourceManger। आपका कोड कुछ इस तरह दिखाई देगा:

private static class CountryHelper
{
    private static ResourceManager rm;

    static CountryHelper()
    {
        rm = new ResourceManager("Countries",  typeof(CountryHelper).Assembly);
    }

    public static Country GetByCode(string code)
    {
        string countryName = rm.GetString(code + ".EnglishName");
        return new Country { Code = code, EnglishName = countryName };
    }
}

इसे थोड़ा और अधिक कुशल बनाने के लिए आप उन सभी को एक साथ लोड कर सकते हैं, जैसे:

private static class CountryHelper
{
    private static Dictionary<string, Country> countries;

    static CountryHelper()
    {
        ResourceManager rm = new ResourceManager("Countries",  typeof(CountryHelper).Assembly);
        string[] codes = rm.GetString("AllCodes").Split("|"); // AU|SE|... 
        countries = countryCodes.ToDictionary(c => c, c => CreateCountry(rm, c));
    }

    public static Country GetByCode(string code)
    {
        return countries[code];
    }

    private static Country CreateCountry(ResourceManager rm, string code)
    {
        string countryName = rm.GetString(code + ".EnglishName");
        return new Country { Code = "SE", EnglishName = countryName };
    }
}

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

यदि यह WPF अनुप्रयोग होता है, तो संसाधन शब्दकोश एक बहुत अधिक स्पष्ट समाधान है।


2

निर्णय वास्तव में है: क्या आप केवल डेवलपर (या किसी बिल्ड सिस्टम तक पहुंच वाले) को संशोधित करने की आवश्यकता होने पर डेटा को संशोधित करना चाहते हैं, या अंतिम उपयोगकर्ता या संभवतः अंतिम उपयोगकर्ता के संगठन में किसी को संशोधित करने में सक्षम होना चाहिए डेटा?

बाद के मामले में, मेरा सुझाव है कि उपयोगकर्ता-पठनीय और उपयोगकर्ता-संपादन योग्य प्रारूप में एक फ़ाइल को उस स्थान पर संग्रहीत किया जाएगा जहां उपयोगकर्ता इसे एक्सेस कर सकता है। जाहिर है जब आप डेटा पढ़ते हैं तो आपको सावधान रहने की आवश्यकता होती है; जो कुछ भी आप पाते हैं वह मान्य डेटा पर भरोसा नहीं किया जा सकता है। मैं शायद JSON को XML पसंद करूंगा; मुझे समझने और सही होने में आसानी होती है। यदि डेटा प्रारूप के लिए कोई संपादक उपलब्ध है, तो आप देख सकते हैं; उदाहरण के लिए यदि आप MacOS X पर एक प्लिस्ट का उपयोग करते हैं तो प्रत्येक उपयोगकर्ता को जो कभी भी डेटा के पास जाना चाहिए, उसके कंप्यूटर पर एक सभ्य संपादक होगा।

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


1

इसका सबसे अच्छा उदाहरण जो मौजूद है, वह शायद WPF है ... आपके फॉर्म XAML में लिखे गए हैं, जो मूल रूप से XML है, सिवाय इसके कि .NET इसे बहुत जल्दी किसी ऑब्जेक्ट प्रतिनिधित्व में फिर से सक्रिय करने में सक्षम है। XAML फाइल को BAML फाइल के रूप में संकलित किया गया है, और इसे ".resource" फाइल में निचोड़ दिया गया है, जो तब असेंबली में एम्बेड किया गया है। (.NET परावर्तक का नवीनतम संस्करण आपको ये फाइलें दिखा सकता है)।

यद्यपि इसका समर्थन करने के लिए कोई महान दस्तावेज नहीं है, MSBuild को वास्तव में XAML फ़ाइल लेने में सक्षम होना चाहिए, इसे BAML में रूपांतरित करना चाहिए, और इसे आपके लिए एम्बेड करना चाहिए (यह सही रूपों के लिए करता है?)।

इसलिए, मेरा दृष्टिकोण यह होगा: अपने डेटा को एक्सएएमएल में संग्रहित करें (यह सिर्फ ऑब्जेक्ट ग्राफ का एक्सएमएल प्रतिनिधित्व है), एक्सएएमएल को एक संसाधन फ़ाइल में सामान दें, और इसे विधानसभा में एम्बेड करें। रनटाइम पर XAML को पकड़ो, और इसे रीहाइड्रेट करने के लिए XamlServices का उपयोग करें। फिर या तो इसे एक स्थिर सदस्य में लपेटें, या डिपेंडेन्सी इंजेक्शन का उपयोग करें यदि आप चाहते हैं कि यह अधिक परीक्षण योग्य हो, तो अपने बाकी कोड से इसका उपभोग करें।

कुछ लिंक जो उपयोगी संदर्भ सामग्री हैं:

  • AL.exe (असेंबलियों में संसाधनों को एम्बेड करने के लिए)
  • Resgen.exe (संसाधनों के लिए .resx फ़ाइलों को परिवर्तित करने के लिए)
  • XamlServices वर्ग

साइड नोट पर, आप वास्तव में app.config, या web.config फ़ाइलों का उपयोग सेटिंग्स तंत्र के माध्यम से यथोचित जटिल वस्तुओं को लोड करने के लिए कर सकते हैं यदि आप चाहते हैं कि डेटा अधिक आसानी से बदला जा सके। और आप फ़ाइल सिस्टम से XAML भी लोड कर सकते हैं।


1

मुझे लगता है कि System.Globalization.CultureInfo.GetCulture (नाम) सिस्टम फ़ाइल से डेटा प्राप्त करने के लिए विंडोज एपीआई को कॉल करेगा।

डेटा को कोड में लोड करने के लिए, जैसे @svick ने कहा था, यदि आप 200 ऑब्जेक्ट लोड करने वाले हैं, तो ज्यादातर मामलों में यह समस्या नहीं होगी, जब तक कि आपका कोड कुछ कम मेमोरी डिवाइस पर नहीं चल रहा हो।

यदि आपका डेटा कभी नहीं बदलता है, तो मेरा अनुभव बस एक सूची / शब्दकोश का उपयोग कर रहा है:

private static readonly Dictionary<string, Country> _countries = new Dictionary<string,Country>();

लेकिन समस्या यह है कि आपको अपने शब्दकोश को इनिशियलाइज़ करने का तरीका खोजने की ज़रूरत है। मुझे लगता है कि यह दर्द बिंदु है।

तो समस्या को "अपना डेटा कैसे उत्पन्न किया जाए?" में बदल दिया जाता है। लेकिन यह आप की जरूरत से संबंधित है।

यदि आप देशों के लिए डेटा उत्पन्न करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं

System.Globalization.CultureInfo.GetCultures()

कलट्रूइन्फो सरणी प्राप्त करें, और आप अपनी आवश्यकताओं के साथ अपने शब्दकोश को इनिशियलाइज़ कर सकते हैं।

और निश्चित रूप से आप कोड को एक स्थैतिक वर्ग में रख सकते हैं, और इस शब्द को स्थिर कंस्ट्रक्टर में आरंभ कर सकते हैं जैसे:

public static class CountryHelper
{
    private static readonly Dictionary<string, Country> _countries;
    static CountryHelper()
    {
        _countries = new Dictionary<string,Country>();
        // initialization code for your dictionary
        System.Globalization.CultureInfo[] cts = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.AllCultures);
        for(int i=0; i < cts.Length; i++)
        {
            _countries.Add(cts[i].Name, new Country(cts[i]));
        }
    }

    public static Country GetCountry(string code)
    {
        Country ct = null;
        if(this._countries.TryGet(code, out ct))
        {
            return ct;
        } else
        {
            Log.WriteDebug("Cannot find country with code '{0}' in the list.", code);
            return null;
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.