System.ArgumentNullException в средствах ResourceManager.GetString

63
5

Мой код:


System.Resources.ResourceManager resourceManager = GetResourceManager();
string str = resourceManager.GetString("delete", new CultureInfo(1033));

В текущем проекте, скомпилированном в .NET 2.0, все работает как исключенное. Переменная str содержит строку ресурса для LCID 1033 - Удалить, это нормально.


Теперь мы обновляемся до .NET 4.0, перекомпилировали проект под целевой платформой .NET 4.0.
Теперь скомпилированный как сборки .NET 4.0, он генерирует исключение System.ArgumentNullException с сообщением Значение не может быть null..Stack trace:


   at System.Threading.Monitor.Enter(Object obj)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)

Интересным здесь является stacktrace, где он указывает на метод внутренней структуры в ResourceManager.InternalGetResourceSet, который вызывает вызов Monitor.Enter с нулевым объектом. Но я вызываю метод GetString с ненулевыми параметрами GetString ( "delete", new CultureInfo (1033)).


Эта ошибка, похоже, похожа на System.ArgumentNullException в System.Threading.Monitor.Enter. Может быть, какая-то ошибка в Monitor.Enter или что-то еще?


Обновление:
Когда я смотрю в отладчике в объекте resourceManager.ResourceSets.Items[2].Value.Table["delete"], он содержит строковое значение "Удалить". свойство Items [2] здесь указывает на LCID 1033. Это означает, что диспетчер ресурсов уже содержит локализованную строку для удаления ключа ресурса на языке 1033. Кто-нибудь знает, где может быть ошибка?

спросил(а) 2021-01-25T14:19:41+03:00 4 месяца, 4 недели назад
1
Решение
64

Я нашел ответ сам. Вот подробности:
У нас есть пользовательская реализация ResourceManager:


public class DatabaseResourceManager : System.Resources.ResourceManager 
{
public DatabaseResourceManager(int applicationID, string bundle)
{
foreach (int languageID in ResourceProvider.Provider.GetLanguages(applicationID))
{
DatabaseResourceReader r = new DatabaseResourceReader(applicationID, bundle, languageID);
ResourceSets.Add(new CultureInfo(languageID), new ResourceSet(r));
}
}

В .NET 2.0 он работает хорошо, но в .NET 4.0 что-то изменилось в реализации ResourceManager.I думаю, что проблема заключается в безпараметрическом конструкторе, который в .NET 2.0 создает экземпляр частного поля this._resourceSets (который позже используется в InternalGetResourceSet для Monitor.Enter). Но в .NET 4.0 без параметров конструктор не создает экземпляр частного поля this._resourceSets и, следовательно, он не работает позже (как описано abobe).

Я должен переписать свой пользовательский менеджер ресурсов, чтобы это получилось:


public class DatabaseResourceManager : System.Resources.ResourceManager 
{
public DatabaseResourceManager(int applicationID, string bundle)
{
ResourceSets = new Hashtable();
this.applicationID = applicationID;
this.bundle = bundle;
}

protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
{
if (this.ResourceSets.Contains(culture.Name))
return this.ResourceSets[culture.Name] as ResourceSet;

lock (syncLock)
{
if (this.ResourceSets.Contains(culture.Name))
return this.ResourceSets[culture.Name] as ResourceSet;

DatabaseResourceReader r = new DatabaseResourceReader(applicationID, bundle, culture.LCID);
ResourceSet rs = new ResourceSet(r);

this.ResourceSets.Add(culture.Name, rs);

return rs;
}
}
}


"Магия" здесь заключается в том, что я должен перезаписать метод InternalGetResourceSet для загрузки моих ресурсов из пользовательского хранилища (db) и возврата "ResourceSet" для указанной культуры. Теперь это работает как шарм.

ответил(а) 2021-01-25T14:19:41+03:00 4 месяца, 4 недели назад
63

Я также считаю, что вы должны объявить и использовать свой собственный словарь для хранения, поскольку ResourceSets помечен как "Устаревший" в .NET 4.0

ответил(а) 2021-01-25T14:19:41+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема