ResourceManager.GetString 内部的 System.ArgumentNullException

发布于 2024-10-05 13:03:32 字数 1577 浏览 5 评论 0原文

我的代码:

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 并显示消息 Value 不能为 null。。堆栈跟踪:

   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 中的方法会导致使用 null 对象调用 Monitor.Enter。但我调用方法 GetString 时参数不为空 GetString("delete", new CultureInfo(1033))

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

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

My code:

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

In current project compiled under .NET 2.0 everything works as excepted. Variable str contains resource string for LCID 1033 - Delete, this is ok.

We are now upgrading to .NET 4.0, recompiled project under target framework .NET 4.0.
Now compiled as .NET 4.0 assemblies, it throws exception System.ArgumentNullException with message Value cannot be 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)

Interesting here is stacktrace, where it points to internal framework method in ResourceManager.InternalGetResourceSet which causes to call Monitor.Enter with null object. But i call method GetString with not null parameters GetString("delete", new CultureInfo(1033)).

This bug seems to be similar to System.ArgumentNullException in System.Threading.Monitor.Enter. Maybe some bug in Monitor.Enter, or something else?

Update:
When i look in debugger at object resourceManager.ResourceSets.Items[2].Value.Table["delete"] then it contains string value "Delete". property Items[2] here pointing to LCID 1033. This means that resource manager already contains localized string for resource key delete in language 1033. Does anybody knows where can be error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暖伴 2024-10-12 13:03:32

我还认为您应该声明并使用自己的字典进行存储,因为 ResourceSets 在 .NET 4.0 下被标记为 Obsolete

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

咋地 2024-10-12 13:03:32

我自己找到了答案。详细信息如下:
我们有这样的 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(稍后在 Monitor.Enter 的 InternalGetResourceSet 中使用)。但在 .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” 。现在它就像一个魅力。

I found answer myself. Here are details:
We have custom implementation of ResourceManager like this:

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));
    }
}

In .NET 2.0 it works well, but in .NET 4.0 something has changed in implementation of ResourceManager.I think that problem is in parameterless constructor which in .NET 2.0 instantiate private field this._resourceSets (which is later used in InternalGetResourceSet for Monitor.Enter). But in .NET 4.0 parameterless constructor does not instantiate private field this._resourceSets and thus it fails later (as described abobe).

I must rewrite my custom resource manager as this to work out:

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;
    }
  }
}

"Magic" here is that i must overwrite method InternalGetResourceSet to load my resources from custom storage (db) and return back "ResourceSet" for specified culture. Now it works like a charm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文