Un marco DI está diseñado para hacer la inyección de dependencia y la localización podría ser solo uno de sus servicios, por lo que en ese caso no hay ninguna razón para no usar para usar un marco de trabajo IMO. Tal vez deberíamos comenzar a discutir la interfaz ILocalResources
proporcionada. Si bien soy partidario de tener soporte de tiempo de compilación, no estoy seguro de que la interfaz suministrada lo ayude, ya que esa interfaz probablemente sea del tipo de su sistema que más cambiará. Y con esa interfaz el tipo/tipos que lo implementan. Tal vez deberías ir con un diseño diferente.
Cuando miramos la mayoría de los marcos/proveedores/fábricas de localización (o lo que sea), todos están basados en cadenas. Debido a esto, pensar en el siguiente diseño:
public interface ILocalResources
{
string GetStringResource(string key);
string GetStringResource(string key, CultureInfo culture);
}
Esto permitirá agregar claves y culturas para el almacén de datos mensaje subyacente, sin cambiar la interfaz. Lo malo es, por supuesto, que nunca deberías cambiar una tecla, porque eso probablemente sea un infierno.
Otro enfoque podría ser un tipo de base abstracta:
public abstract class LocalResources
{
public string OkMessage { get { return this.GetString("OK"); } }
public string CancelMessage { get { return this.GetString("Cancel"); } }
...
protected abstract string GetStringResource(string key,
CultureInfo culture);
private string GetString(string key)
{
Culture culture = CultureInfo.CurrentCulture;
string resource = GetStringResource(key, culture);
// When the resource is not found, fall back to the neutral culture.
while (resource == null && culture != CultureInfo.InvariantCulture)
{
culture = culture.Parent;
resource = this.GetStringResource(key, culture);
}
if (resource == null) throw new KeyNotFoundException(key);
return resource;
}
}
y la aplicación de este tipo podría tener este aspecto:
public sealed class SqlLocalResources : LocalResources
{
protected override string GetStringResource(string key,
CultureInfo culture)
{
using (var db = new LocalResourcesContext())
{
return (
from resource in db.StringResources
where resource.Culture == culture.Name
where resource.Key == key
select resource.Value).FirstOrDefault();
}
}
}
Este enfoque tiene lo mejor de ambos mundos, ya que las claves ganaron' Estar disperso por la aplicación y agregar nuevas propiedades solo tiene que hacerse en un solo lugar. El uso de la biblioteca de favorite DI, se puede registrar una aplicación como esta:
container.RegisterSingleton<LocalResources>(new SqlLocalResources());
Y puesto que el tipo LocalResources
tiene exactamente un método abstracto que hace todo el trabajo, es fácil crear un decorador que se suma el almacenamiento en caché para evitar que solicita los mismos datos de la base de datos:
public sealed class CachedLocalResources : LocalResources
{
private readonly Dictionary<CultureInfo, Dictionary<string, string>> cache =
new Dictionary<CultureInfo, Dictionary<string, string>>();
private readonly LocalResources decoratee;
public CachedLocalResources(LocalResources decoratee) { this.decoratee = decoratee; }
protected override string GetStringResource(string key, CultureInfo culture) {
lock (this.cache) {
string res;
var cultureCache = this.GetCultureCache(culture);
if (!cultureCache.TryGetValue(key, out res)) {
cultureCache[key] = res= this.decoratee.GetStringResource(key, culture);
}
return res;
}
}
private Dictionary<string, string> GetCultureCache(CultureInfo culture) {
Dictionary<string, string> cultureCache;
if (!this.cache.TryGetValue(culture, out cultureCache)) {
this.cache[culture] = cultureCache = new Dictionary<string, string>();
}
return cultureCache;
}
}
puede aplicar el decorador de la siguiente manera:
container.RegisterSingleton<LocalResources>(
new CachedLocalResources(new SqlLocalResources()));
no hacer
e que este decorador guarda en caché los recursos de cadena de forma indefinida, lo que puede causar pérdidas de memoria, por lo que desea ajustar las cadenas en instancias WeakReference
o tener algún tipo de tiempo de espera de caducidad. Pero la idea es que puede aplicar el almacenamiento en caché sin tener que cambiar ninguna implementación existente.
Espero que esto ayude.
Alternativamente, también podría implementar métodos de extensión para la interfaz 'ILocalResources', pero ese inconveniente es que tendrá métodos en lugar de propiedades. Pero eso probablemente no sería tan malo. – Steven