我的代码:
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 ,消息值不能为空。 .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 中的内部框架方法,这导致使用null对象调用 Monitor.Enter 。但我调用方法 GetString 非空参数 GetString(“delete”,new CultureInfo(1033))。
此错误似乎与System.ArgumentNullException in System.Threading.Monitor.Enter类似。可能是Monitor.Enter中的一些错误,或其他什么?
更新:
当我在对象resourceManager.ResourceSets.Items[2].Value.Table["delete"]
中查看调试器时,它包含字符串值“Delete”。属性项目[2]这里指向LCID 1033.这意味着资源管理器已经包含语言 1033 中资源键 delete 的本地化字符串。有谁知道哪里可以出错?
答案 0 :(得分:1)
我自己找到了答案。这是详细信息: 我们有这样的自定义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的实现发生了一些变化。我认为问题出在无参数构造函数中,在.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”。现在它就像一个魅力。
答案 1 :(得分:1)
我还认为您应该声明并使用自己的字典进行存储,因为在.NET 4.0下将ResourceSets标记为已过时