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がスローされ、 Value cannot be 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が呼び出されます。しかし、null パラメーターではないメソッド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でリソース キーを削除するためのローカライズされた文字列が既に含まれていることを意味します。どこでエラーが発生するか知っている人はいますか?

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をインスタンス化するパラメーターなしのコンストラクターにあると思います(これは後でMonitorのInternalGetResourceSetで使用されます)。入る)。しかし、.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

また、ResourceSets は .NET 4.0 では Obsolete としてマークされているため、ストレージ用に独自の辞書を宣言して使用する必要があると思います。

于 2011-05-29T07:30:48.003 に答える