System.ArgumentNullexception in ResourceManager.getString Internals
-
29-09-2019 - |
質問
私のコード:
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 メッセージ付き 値はヌルにすることはできません。。スタックトレース:
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 それは呼び出します Monitor.enter nullオブジェクト付き。しかし、私は方法を呼び出します GetString ヌルパラメーターではありません GetString( "Delete"、New CultureInfo(1033)).
このバグは似ているようです system.threading.monitor.enterのsystem.argumentnullexception. 。たぶん、モニターのバグ。
更新:オブジェクトでデバッガーを見るとき resourceManager.ResourceSets.Items[2].Value.Table["delete"]
次に、文字列値「削除」が含まれます。プロパティアイテム[2]ここでは、LCID 1033を指しています。これは、リソースマネージャーにリソースキー用のローカライズされた文字列が既に含まれていることを意味します 消去 言語で 1033. 。エラーがどこにあるか知っている人はいますか?
解決
また、リソースセットは.NET 4.0の下で時代遅れとしてマークされているため、ストレージに独自の辞書を宣言して使用する必要があると思います。
他のヒント
私は自分自身に答えるのを見つけました。詳細は次のとおりです。このような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の実装で何かが変更されました。 this._resourcesets (後に使用されます internalgetResourceset Monitor.enter用)。しかし、.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)からリソースをロードし、指定されたカルチャーの「リソースセット」を返します。今では魅力のように機能します。