ResourceManager.GetString内部的System.ArgumentNullException

时间:2010-12-01 10:12:10

标签: .net c#-4.0 locking resourcebundle

我的代码:

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 的本地化字符串。有谁知道哪里可以出错?

2 个答案:

答案 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标记为已过时