Kilka razy w przeszłości chciałem przechowywać dane w kodzie. Byłyby to dane, które rzadko się zmieniają i są wykorzystywane w miejscach, w których dostęp do bazy danych jest niemożliwy, praktyczny lub pożądany. Małym przykładem byłoby przechowywanie listy krajów. W tym celu możesz zrobić coś takiego:
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);
}
}
W przeszłości nie mogłem tego robić, ponieważ zestawy danych były stosunkowo małe, a obiekty dość proste. Teraz pracuję z czymś, co będzie miało bardziej złożone obiekty (5-10 właściwości każda, niektóre właściwości to słowniki) i łącznie około 200 obiektów.
Same dane zmieniają się bardzo rzadko, a kiedy się zmieniają, nie są nawet tak ważne. Tak więc włączenie go do następnej wersji jest w porządku.
Planuję użyć T4 lub ERB lub innego rozwiązania szablonowego, aby zmienić moje źródło danych w coś, co jest przechowywane statycznie w zestawie.
Wygląda na to, że moje opcje są
- Przechowuj dane w formacie XML. Skompiluj plik XML jako zasób zestawu. Załaduj dane w razie potrzeby, zapisz załadowane dane w Słowniku w celu zapewnienia wydajności wielokrotnego użytku.
- Wygeneruj jakiś statyczny obiekt lub obiekty, które zostaną zainicjowane podczas uruchamiania.
Jestem prawie pewien, że rozumiem wpływ opcji 1. na wydajność. Przynajmniej mam przeczucie, że nie miałaby ona znakomitej wydajności.
Jeśli chodzi o opcję 2, nie wiem, co robić. Nie wiem wystarczająco dużo o wewnętrznych elementach środowiska .NET, aby wiedzieć, jak najlepiej przechowywać te dane w kodzie C # i jak najlepiej je zainicjować. Rozglądałem się za pomocą odbłyśnika .NET, aby zobaczyć, jak System.Globalization.CultureInfo.GetCulture(name)
działa, ponieważ w rzeczywistości jest to bardzo podobny przepływ pracy do tego, czego chcę. Niestety szlak ten zakończył się na extern
, więc nie ma tam żadnych wskazówek. Czy inicjowanie właściwości statycznej za pomocą wszystkich danych, tak jak w moim przykładzie, jest właściwą drogą? A może lepiej byłoby tworzyć obiekty na żądanie, a następnie buforować je w ten sposób?
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();
}
Zaletą tworzenia ich naraz w statycznym elemencie jest to, że możesz użyć LINQ lub cokolwiek innego, aby spojrzeć na wszystkie obiekty i zapytać je, jeśli chcesz. Chociaż podejrzewam, że robienie tego ma negatywny wpływ na wydajność uruchamiania. Mam nadzieję, że ktoś ma z tym doświadczenie i może podzielić się swoimi opiniami!
Odpowiedzi:
Wybrałbym opcję pierwszą. Jest prosty i łatwy do odczytania. Ktoś inny patrząc na twój kod zrozumie go od razu. W razie potrzeby łatwiej będzie również zaktualizować dane XML. (Dodatkowo możesz pozwolić użytkownikowi na ich aktualizację, jeśli masz ładny interfejs i pliki są przechowywane osobno)
Zoptymalizuj go tylko, jeśli potrzebujesz - przedwczesna optymalizacja jest zła :)
źródło
Biorąc pod uwagę, że są to zasadniczo pary klucz-wartość, zalecam przechowywanie tych ciągów jako pliku zasobów osadzonego w zestawie podczas kompilacji. Następnie możesz je odczytać za pomocą
ResourceManger
. Twój kod wyglądałby mniej więcej tak:Aby zwiększyć wydajność, możesz załadować je wszystkie naraz, w następujący sposób:
To pomoże Ci się dużo , jeśli kiedykolwiek potrzeba, aby Twoje wsparcie dla aplikacji w wielu językach.
Jeśli jest to aplikacja WPF, słownik zasobów jest znacznie bardziej oczywistym rozwiązaniem.
źródło
Decyzja jest naprawdę: Czy chcesz, aby tylko programista (lub ktokolwiek mający dostęp do systemu kompilacji) modyfikował dane, gdy trzeba je modyfikować, czy też użytkownik końcowy lub inna osoba w organizacji użytkownika końcowego może modyfikować dane?
W tym drugim przypadku sugerowałbym, aby plik w formacie czytelnym dla użytkownika i edytowalnym dla użytkownika był przechowywany w miejscu, w którym użytkownik może uzyskać do niego dostęp. Oczywiście podczas odczytywania danych należy zachować ostrożność; cokolwiek znajdziesz, nie można ufać, że są poprawnymi danymi. Prawdopodobnie wolałbym JSON niż XML; Łatwiej mi zrozumieć i dobrze zrozumieć. Możesz sprawdzić, czy jest dostępny edytor formatu danych; na przykład, jeśli korzystasz z listy odtwarzania w systemie MacOS X, wówczas każdy użytkownik, który powinien kiedykolwiek zbliżyć się do danych, będzie miał porządny edytor na swoim komputerze.
W pierwszym przypadku, jeśli dane są częścią twojej kompilacji, tak naprawdę to nie robi różnicy. Rób to, co dla ciebie najwygodniejsze. W C ++ zapisywanie danych przy minimalnym obciążeniu jest jednym z niewielu miejsc, w których dozwolone są makra. Jeśli prace związane z utrzymywaniem danych są wykonywane przez stronę trzecią, możesz wysłać im pliki źródłowe, pozwolić im je edytować, a następnie odpowiadasz za ich sprawdzenie i wykorzystanie w swoim projekcie.
źródło
Najlepszym tego przykładem jest prawdopodobnie WPF ... Twoje formularze są napisane w XAML, który jest w zasadzie XML, z wyjątkiem tego, że .NET jest w stanie bardzo szybko uwodnić go do reprezentacji obiektu. Plik XAML jest kompilowany do pliku BAML i wyciskany do pliku „.resources”, który jest następnie osadzany w zestawie (najnowsza wersja reflektora .NET może wyświetlać te pliki).
Chociaż nie istnieje żadna świetna dokumentacja na jego poparcie, MSBuild powinien być w stanie pobrać plik XAML, przekonwertować go na BAML i osadzić dla ciebie (czy robi to poprawnie dla formularzy?).
Moje podejście brzmiałoby: przechowuj dane w XAML (to tylko reprezentacja XML wykresu obiektowego), wrzuć XAML do pliku zasobów i umieść je w zestawie. W czasie wykonywania weź XAML i użyj XamlServices, aby go ponownie uwodnić. Następnie albo zawiń go w element statyczny, albo użyj Dependency Injection, jeśli chcesz, aby był bardziej testowalny, aby zużyć go z pozostałej części kodu.
Kilka linków, które są przydatnym materiałem referencyjnym:
Na marginesie, możesz faktycznie użyć plików app.config lub web.config, aby załadować rozsądnie skomplikowane obiekty za pomocą mechanizmu ustawień, jeśli chcesz łatwiej zmienić dane. Możesz także załadować XAML z systemu plików.
źródło
Wydaje mi się, że System.Globalization.CultureInfo.GetCulture (nazwa) wywołałby interfejsy API systemu Windows w celu pobrania danych z pliku systemowego.
W przypadku ładowania danych do kodu, tak jak powiedział @svick, jeśli masz zamiar załadować 200 obiektów, w większości przypadków nie będzie problemu, chyba że Twój kod działa na niektórych urządzeniach z małą ilością pamięci.
Jeśli Twoje dane nigdy się nie zmieniają, moje doświadczenie polega na użyciu listy / słownika, takiego jak:
Problem polega jednak na tym, że musisz znaleźć sposób na zainicjowanie słownika. Myślę, że to jest bolączka.
Problem został zmieniony na „Jak wygenerować dane?”. Ale to dotyczy tego, czego potrzebujesz.
Jeśli chcesz generować dane dla krajów, możesz skorzystać z
zdobądź tablicę CultrueInfo, a będziesz mógł zainicjować słownik według własnych potrzeb.
Oczywiście możesz umieścić kod w klasie statycznej i zainicjować słownik w konstruktorze statycznym, np .:
źródło