1

我的代码:

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

在 .NET 2.0 下编译的当前项目中,一切正常。变量str包含 LCID 1033 - Delete的资源字符串,这没关系。

我们现在正在升级到 .NET 4.0,在目标框架 .NET 4.0 下重新编译项目。现在编译为 .NET 4.0 程序集,它会抛出异常System.ArgumentNullException,消息值不能为空。。堆栈跟踪:

   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)

这里有趣的是堆栈跟踪,它指向ResourceManager.InternalGetResourceSet中的内部框架方法,这会导致调用Monitor.Enter与空对象。但是我用非空参数调用GetString ("delete", new CultureInfo(1033))方法。

此错误似乎类似于System.Threading.Monitor.Enter 中的 System.ArgumentNullException。也许是 Monitor.Enter 中的一些错误,或者其他什么?

更新:当我在调试器中查看对象时resourceManager.ResourceSets.Items[2].Value.Table["delete"],它包含字符串值“删除”。此处的属性 Items[2] 指向 LCID 1033。这意味着资源管理器已经包含语言1033中资源键删除的本地化字符串。有谁知道哪里可能出错?

4

2 回答 2

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。进入)。但是在 .NET 4.0 中,无参数构造函数不会实例化私有字段this._resourceSets,因此它稍后会失败(如上文所述)。

我必须重写我的自定义资源管理器才能解决:

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”。现在它就像一个魅力。

于 2010-12-01T13:47:03.277 回答
1

I also think that you should declare and use your own dictionary for storage since ResourceSets is marked as Obsolete under .NET 4.0

于 2011-05-29T07:30:48.003 回答