Algunas veces en mi pasado he querido almacenar datos en código. Estos serían datos que rara vez cambian y se utilizan en lugares donde el acceso a una base de datos no es posible, práctico o deseable. Un pequeño ejemplo sería almacenar una lista de países. Para eso podrías hacer algo como:
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);
}
}
Me salí con la suya en el pasado porque los conjuntos de datos eran relativamente pequeños y los objetos bastante simples. Ahora estoy trabajando con algo que tendrá objetos más complejos (5 - 10 propiedades cada uno, algunas propiedades son diccionarios) y alrededor de 200 objetos en total.
Los datos en sí mismos cambian muy raramente y cuando cambian, en realidad ni siquiera es tan importante. Así que pasarlo a la próxima versión de lanzamiento está perfectamente bien.
Estoy planeando usar T4 o ERB o alguna otra solución de plantillas para convertir mi fuente de datos en algo que esté almacenado estáticamente en el ensamblaje.
Parece que mis opciones son
- Almacene los datos en XML. Compile el archivo XML como recurso de ensamblaje. Cargue los datos según sea necesario, almacene los datos cargados en un diccionario para el rendimiento de uso repetido.
- Genere algún tipo de objeto estático u objetos que se inicializan al inicio.
Estoy bastante seguro de que entiendo las implicaciones de rendimiento de la opción 1. Al menos, mi presentimiento es que no tendría un rendimiento estelar.
En cuanto a la opción 2, no sé qué hacer. No sé lo suficiente sobre los componentes internos de .NET Framework para conocer la mejor manera de almacenar realmente estos datos en código C # y las mejores formas de inicializarlos. Busqué usando .NET reflector para ver cómo System.Globalization.CultureInfo.GetCulture(name)
funciona, ya que este es realmente un flujo de trabajo muy similar al que quiero. Desafortunadamente, ese rastro terminó en un extern
, así que no hay pistas allí. ¿Inicializar una propiedad estática con todos los datos, como en mi ejemplo, es el camino a seguir? ¿O sería mejor crear los objetos a pedido y luego almacenarlos en caché, de esta manera?
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();
}
La ventaja de crearlos a la vez en un miembro estático es que puede usar LINQ o cualquier otra cosa para ver todos los objetos y consultarlos si lo desea. Aunque sospecho que hacer esto tiene una penalización de rendimiento de inicio. ¡Espero que alguien tenga experiencia con esto y pueda compartir sus opiniones!
Respuestas:
Yo iría con la opción uno. Es simple y fácil de leer. Alguien más que vea su código lo entenderá de inmediato. También será más fácil actualizar sus datos XML si es necesario. (Además, puede permitir que el usuario las actualice si tiene un buen front-end y almacena los archivos por separado)
Optimícelo solo si lo necesita: la optimización prematura es mala :)
fuente
Dado que estos son esencialmente pares clave-valor, recomiendo almacenar estas cadenas como un archivo de recursos incrustado en su ensamblaje en tiempo de compilación. Luego puede leerlos usando a
ResourceManger
. Su código se vería así:Para hacerlo un poco más eficiente, puede cargarlos todos a la vez, así:
Esto lo ayudará mucho si alguna vez necesita hacer que su aplicación sea compatible con varios idiomas.
Si se trata de una aplicación WPF, un diccionario de recursos es una solución mucho más obvia.
fuente
La decisión es realmente: ¿Desea que solo el desarrollador (o cualquier persona con acceso a un sistema de compilación) modifique los datos cuando sea necesario modificarlos, o si un usuario final o posiblemente alguien de la organización del usuario final pueda modificar los datos? ¿datos?
En el último caso, sugeriría que un archivo en formato legible y editable por el usuario se almacene en un lugar donde el usuario pueda acceder a él. Obviamente cuando lees los datos debes tener cuidado; no se puede confiar en que lo que encuentre sea información válida. Probablemente prefiera JSON a XML; Me resulta más fácil de entender y acertar. Puede verificar si hay un editor disponible para el formato de datos; por ejemplo, si usa una lista en MacOS X, cada usuario que alguna vez deba acercarse a los datos tendrá un editor decente en su computadora.
En el primer caso, si los datos son parte de su compilación, realmente no hace la diferencia. Haz lo que sea más conveniente para ti. En C ++, escribir los datos con una sobrecarga mínima es uno de los pocos lugares donde se permiten macros. Si el trabajo de mantenimiento de los datos es realizado por un tercero, puede enviarles los archivos de origen, dejar que los editen, y luego es responsable de verificarlos y usarlos en su proyecto.
fuente
El mejor ejemplo de esto que existe es probablemente WPF ... Sus formularios están escritos en XAML, que es básicamente XML, excepto que .NET puede rehidratarlo en una representación de objeto muy rápidamente. El archivo XAML se compila en un archivo BAML y se comprime en el archivo ".resources", que luego se incrusta en el ensamblado (la última versión de .NET reflector puede mostrarle estos archivos).
Aunque no hay ninguna documentación excelente que lo respalde, MSBuild debería de hecho poder tomar un archivo XAML, convertirlo a BAML e incrustarlo por usted (¿lo hace para los formularios, verdad?).
Entonces, mi enfoque sería: almacenar sus datos en XAML (es solo una representación XML de un gráfico de objeto), introducir ese XAML en un archivo de recursos e incrustarlo en el ensamblado. En tiempo de ejecución, tome el XAML y use XamlServices para rehidratarlo. Luego, envuélvalo en un miembro estático o use la Inyección de dependencia si desea que sea más comprobable, para consumirlo del resto de su código.
Algunos enlaces que son material de referencia útil:
Como nota al margen, en realidad puede usar los archivos app.config o web.config para cargar objetos razonablemente complejos a través del mecanismo de configuración si desea que los datos se cambien más fácilmente. Y también puede cargar XAML desde el sistema de archivos.
fuente
Supongo que System.Globalization.CultureInfo.GetCulture (nombre) llamaría a las API de Windows para obtener los datos de un archivo del sistema.
Para cargar los datos en el código, como había dicho @svick, si está a punto de cargar 200 objetos, no será un problema en la mayoría de los casos, a menos que su código se ejecute en algunos dispositivos con poca memoria.
Si sus datos nunca cambian, mi experiencia es simplemente usar una lista / diccionario como:
Pero el problema es que necesita encontrar una manera de inicializar su diccionario. Supongo que este es el punto de dolor.
Entonces, el problema se cambia a "¿Cómo generar sus datos?". Pero esto se relaciona con lo que necesitas.
Si desea generar datos para los países, puede usar el
obtenga la matriz CultrueInfo y podrá inicializar su diccionario con sus necesidades.
Y, por supuesto, podría poner el código en una clase estática e inicializar el diccionario en el constructor estático como:
fuente