Рамка DI построена так, чтобы сделать инъекцию зависимостей, и локализация могла бы быть только одной из ваших услуг, поэтому в этом случае нет причин не для использования каркаса DI IMO. Возможно, нам стоит начать обсуждать предоставленный интерфейс ILocalResources
. Хотя я сторонник поддержки времени компиляции, я не уверен, что предоставленный интерфейс вам поможет, потому что этот интерфейс будет, вероятно, типом вашей системы, который изменит больше всего. И с этим интерфейсом тип/типы, которые его реализуют. Возможно, вы должны пойти с другим дизайном.
Когда мы смотрим на большинство локализационных фреймворков/поставщиков/фабрик (или что-то еще), все они основаны на строках. Из-за этого, подумайте о следующем дизайне:
public interface ILocalResources
{
string GetStringResource(string key);
string GetStringResource(string key, CultureInfo culture);
}
Это позволит вам добавить ключи и культуры в базовом хранилище данных сообщения, без изменения интерфейса. Недостаток - это, конечно, что вы никогда не должны менять ключ, потому что это, вероятно, будет чертовски.
Другой подход может быть абстрактным базовым типом:
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;
}
}
И реализация этого типа может выглядеть следующим образом:
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();
}
}
}
Этот подход имеет лучшее из обоих миров, потому что выиграл ключи» t разбросано через приложение, и добавление новых свойств должно быть сделано только в одном месте. Использование favorite библиотеки DI, вы можете зарегистрировать реализацию так:
container.RegisterSingleton<LocalResources>(new SqlLocalResources());
А поскольку LocalResources
типа имеет ровно один абстрактный метод, который делает всю работу, это легко создать декоратор, который добавляет кэширование для предотвращения запроса одни и те же данные из базы данных:
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;
}
}
Вы можете применить декоратор следующим образом:
container.RegisterSingleton<LocalResources>(
new CachedLocalResources(new SqlLocalResources()));
не e, что этот декоратор бесконечно кэширует строковые ресурсы, что может вызвать утечку памяти, поэтому вы хотите обернуть строки в WeakReference
экземплярах или иметь какой-то тайм-аут истечения срока действия на нем. Но идея состоит в том, что вы можете применять кеширование без необходимости изменять существующую реализацию.
Надеюсь, это поможет.
В качестве альтернативы вы также можете реализовать методы расширения для интерфейса «ILocalResources», но этот недостаток заключается в том, что у вас будут методы вместо свойств. Но это, наверное, не так уж плохо. – Steven