การจัดเก็บข้อมูลในรหัส


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 ฉันไม่รู้จะทำอย่างไร ฉันไม่รู้เกี่ยวกับ internals ของ. NET Framework เพื่อทราบวิธีที่ดีที่สุดในการจัดเก็บข้อมูลนี้ในรหัส C # และวิธีที่ดีที่สุดในการเริ่มต้นมัน ฉันแหย่ไปรอบ ๆ โดยใช้. NET reflector เพื่อดูว่ามันSystem.Globalization.CultureInfo.GetCulture(name)ทำงานอย่างไรจริง ๆ แล้วนี่เป็นเวิร์กโฟลว์ที่คล้ายกันมากกับสิ่งที่ฉันต้องการ น่าเสียดายที่เส้นทางนั้นจบลงด้วยการ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 วัตถุ? ฉันไม่คิดว่าคุณต้องกังวลเกี่ยวกับประสิทธิภาพโดยเฉพาะอย่างยิ่งหากเป็นค่าใช้จ่ายครั้งเดียว
svick

1
คุณมีตัวเลือกอื่นซึ่งก็คือการเก็บวัตถุในรหัสจากนั้นส่งผ่านการอ้างอิงถึงการฉีดผ่านพึ่งพาเป็นปกติ ด้วยวิธีนี้ถ้าคุณต้องการเปลี่ยนวิธีการสร้างพวกเขาคุณไม่มีการอ้างอิงแบบคงที่ที่ชี้ไปยังพวกเขาโดยตรงจากทุกที่
Amy Blankenship

@svick: จริง ฉันอาจระมัดระวังเรื่องการแสดงมากเกินไป
mroach

@AmyBlankenship ฉันมักจะใช้วิธีการช่วยเหลือ แต่ DI เป็นความคิดที่ดี ฉันไม่ได้คิดถึงมัน ฉันจะทำแบบนั้นและดูว่าฉันชอบลวดลายไหม ขอบคุณ!
mroach

" ข้อมูลมีการเปลี่ยนแปลงน้อยมากและเมื่อมันเปลี่ยนไปมันก็ไม่ได้สำคัญขนาดนั้นเลย " บอกกับบอสเนีย Serbs, Croats, Ukranians, ซูดานใต้, อดีตเยเมนใต้, อดีตโซเวียตและคณะ บอกกับโปรแกรมเมอร์ทุกคนที่ต้องรับมือกับการเปลี่ยนเป็นสกุลเงินยูโรหรือผู้เขียนโปรแกรมที่อาจต้องจัดการกับทางออกที่มีศักยภาพของกรีซ ข้อมูลอยู่ในโครงสร้างข้อมูล ไฟล์ XML ทำงานได้ดีและสามารถเปลี่ยนแปลงได้ง่าย เช่นเดียวกันกับฐานข้อมูล SQL
Ross Patterson

คำตอบ:


11

ฉันจะไปกับตัวเลือกที่หนึ่ง ง่ายและอ่านง่าย คนอื่นมองที่รหัสของคุณจะเข้าใจได้ทันที นอกจากนี้ยังจะง่ายต่อการอัปเดตข้อมูล XML ของคุณหากต้องการ (นอกจากนี้คุณสามารถให้ผู้ใช้อัปเดตพวกเขาหากคุณมีส่วนหน้าที่ดีและเก็บไฟล์แยกต่างหาก)

ปรับให้เหมาะสมก็ต่อเมื่อคุณต้องการ - การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นสิ่งที่เลวร้าย :)


3
หากคุณกำลังเขียน C # แสดงว่าคุณกำลังเรียกใช้บนแพลตฟอร์มที่สามารถแยกวิเคราะห์ XML ขนาดเล็กได้อย่างรวดเร็ว ดังนั้นจึงไม่คุ้มค่ากับปัญหาเกี่ยวกับประสิทธิภาพ
James Anderson

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; ฉันเข้าใจและเข้าใจได้ง่ายขึ้น คุณอาจตรวจสอบว่ามีตัวแก้ไขสำหรับรูปแบบข้อมูลหรือไม่ ตัวอย่างเช่นถ้าคุณใช้ plist บน MacOS X ผู้ใช้ทุกคนที่ควรเข้าใกล้ข้อมูลจะมีเครื่องมือแก้ไขที่ดีในคอมพิวเตอร์ของเขา

ในกรณีแรกถ้าข้อมูลเป็นส่วนหนึ่งของงานสร้างของคุณมันก็ไม่ได้สร้างความแตกต่างจริงๆ ทำสิ่งที่สะดวกที่สุดสำหรับคุณ ใน C ++ การเขียนข้อมูลที่มีค่าใช้จ่ายน้อยที่สุดเป็นหนึ่งในไม่กี่แห่งที่อนุญาตให้ใช้แมโครได้ หากบุคคลที่สามทำการรักษาข้อมูลไว้คุณสามารถส่งไฟล์ต้นฉบับให้พวกเขาแก้ไขและคุณจะต้องรับผิดชอบในการตรวจสอบและใช้งานในโครงการของคุณ


1

ตัวอย่างที่ดีที่สุดของสิ่งนี้ที่มีอยู่ก็น่าจะเป็น WPF ... รูปแบบของคุณถูกเขียนใน XAML ซึ่งโดยทั่วไปคือ XML ยกเว้นว่า. NET จะสามารถคืนรูปให้เป็นตัวแทนวัตถุได้อย่างรวดเร็ว ไฟล์ XAML ถูกคอมไพล์เป็นไฟล์ BAML และบีบอัดเป็นไฟล์ ". resources" ซึ่งจะถูกฝังอยู่ภายในแอสเซมบลี (เวอร์ชั่นล่าสุดของ. NET reflector สามารถแสดงไฟล์เหล่านี้ได้)

แม้ว่าจะไม่มีเอกสารประกอบที่ยอดเยี่ยมที่จะสนับสนุน แต่ MSBuild ควรจะสามารถใช้ไฟล์ XAML แปลงเป็น BAML และฝังไว้ให้คุณได้

ดังนั้นแนวทางของฉันคือ: เก็บข้อมูลของคุณใน XAML (เป็นเพียงการแสดง XML ของกราฟวัตถุ) สิ่งที่ XAML ลงในไฟล์ทรัพยากรและฝังไว้ในแอสเซมบลี ที่รันไทม์คว้า XAML และใช้ XamlServices เพื่อคืนมัน จากนั้นห่อมันในสมาชิกแบบคงที่หรือใช้การฉีดพึ่งพาถ้าคุณต้องการที่จะทดสอบได้มากขึ้นเพื่อใช้มันจากส่วนที่เหลือของรหัสของคุณ

ลิงค์เล็ก ๆ น้อย ๆ ที่เป็นเอกสารอ้างอิงที่มีประโยชน์:

  • AL.exe (สำหรับการฝังทรัพยากรในแอสเซมบลี)
  • Resgen.exe (สำหรับการแปลงไฟล์. resxเป็นทรัพยากร)
  • คลาส XamlServices

ในบันทึกย่อด้านข้างคุณสามารถใช้ไฟล์ app.config หรือ web.config เพื่อโหลดวัตถุที่ซับซ้อนพอสมควรผ่านกลไกการตั้งค่าหากคุณต้องการเปลี่ยนข้อมูลได้ง่ายขึ้น และคุณยังสามารถโหลด XAML จากระบบไฟล์


1

ฉันเดาว่า System.Globalization.CultureInfo.GetCulture (ชื่อ) จะเรียก Windows APIs เพื่อรับข้อมูลจากไฟล์ระบบ

สำหรับการโหลดข้อมูลในรหัสเช่นเดียวกับ @svick ได้กล่าวไว้ว่าถ้าคุณกำลังจะโหลดวัตถุ 200 รายการมันจะไม่เป็นปัญหาในกรณีส่วนใหญ่ยกเว้นว่ารหัสของคุณทำงานบนอุปกรณ์หน่วยความจำต่ำ

หากข้อมูลของคุณไม่เปลี่ยนแปลงประสบการณ์ของฉันคือการใช้รายการ / พจนานุกรมเช่น:

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

แต่ปัญหาคือคุณต้องหาวิธีเริ่มต้นพจนานุกรมของคุณ ฉันเดาว่านี่เป็นจุดปวด

ดังนั้นปัญหาจึงเปลี่ยนเป็น "วิธีสร้างข้อมูลของคุณ" แต่สิ่งนี้เกี่ยวข้องกับสิ่งที่คุณต้องการ

หากคุณต้องการสร้างข้อมูลสำหรับประเทศคุณสามารถใช้

System.Globalization.CultureInfo.GetCultures()

รับอาร์เรย์ CultrueInfo และคุณสามารถกำหนดค่าเริ่มต้นพจนานุกรมตามความต้องการของคุณ

และแน่นอนคุณสามารถใส่รหัสในคลาสแบบคงที่และเริ่มต้นพจนานุกรมในตัวสร้างแบบคงที่เช่น:

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;
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.