2

しばらく前 (私が足を踏み外したとき)に、リソース文字列を使用した場合のパフォーマンス オーバーヘッドに関して、リソース ファイル (.resx) を使用した場合のパフォーマンス オーバーヘッドについて次の質問をしました。私は賛成票を投じた回答を得て、その回答を正しいものとしました。ただし、以前は、エラー状態で呼び出され、パフォーマンスが重要ではないメッセージ文字列をローカライズしていました。現在は、コード「パワーハウス」(多くのパフォーマンスが重要なコード、組み込みループなど) にローカライズを実装するよう求められています。

これをさらに詳しく調べる時間があり、次のようなリソースを呼び出すことに気付きました

Resources.MessageStrings.SomeResourceName

MessageStrings.Designer.csを使用する自動生成コードへの呼び出しを参照するだけです。

internal static string SomeResourceName {
    get {
        return ResourceManager.GetString("SomeResourceName", resourceCulture);}
}

深く掘り下げて、次の場所にあるものを逆コンパイルすると思いResourceManagerました

C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\mscorlib.dll

GetString()が行われていたかを確認するには [リソース文字列を本当にキャッシュしていますか? ]。逆コンパイル、私は見つけます

[__DynamicallyInvokable]
public virtual string GetString(string name, CultureInfo culture)
{
  if (name == null)
    throw new ArgumentNullException("name");
  if (ResourceManager.s_IsAppXModel && object.ReferenceEquals((object) culture, (object) CultureInfo.CurrentUICulture))
    culture = (CultureInfo) null;
  if (this._bUsingModernResourceManagement)
  {
    if (this._PRIonAppXInitialized)
      return this.GetStringFromPRI(name, culture == null ? (string) null : culture.Name, this._neutralResourcesCulture.Name);
    if (this._PRIExceptionInfo == null || this._PRIExceptionInfo._PackageSimpleName == null || this._PRIExceptionInfo._ResWFile == null)
      throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
    throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", (object) this._PRIExceptionInfo._ResWFile, (object) this._PRIExceptionInfo._PackageSimpleName));
  }
  else
  {
    if (culture == null)
      culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
    if (FrameworkEventSource.IsInitialized)
      FrameworkEventSource.Log.ResourceManagerLookupStarted(this.BaseNameField, this.MainAssembly, culture.Name);
    ResourceSet resourceSet1 = this.GetFirstResourceSet(culture);
    if (resourceSet1 != null)
    {
      string @string = resourceSet1.GetString(name, this._ignoreCase);
      if (@string != null)
        return @string;
    }
    foreach (CultureInfo culture1 in new ResourceFallbackManager(culture, this._neutralResourcesCulture, true))
    {
      ResourceSet resourceSet2 = this.InternalGetResourceSet(culture1, true, true);
      if (resourceSet2 != null)
      {
        if (resourceSet2 != resourceSet1)
        {
          string @string = resourceSet2.GetString(name, this._ignoreCase);
          if (@string != null)
          {
            if (this._lastUsedResourceCache != null)
            {
              lock (this._lastUsedResourceCache)
              {
                this._lastUsedResourceCache.lastCultureName = culture1.Name;
                this._lastUsedResourceCache.lastResourceSet = resourceSet2;
              }
            }
            return @string;
          }
          else
            resourceSet1 = resourceSet2;
        }
      }
      else
        break;
    }
    if (FrameworkEventSource.IsInitialized)
      FrameworkEventSource.Log.ResourceManagerLookupFailed(this.BaseNameField, this.MainAssembly, culture.Name);
    return (string) null;
  }
}

上記のコードには、文字列を「キャッシュ」していることを示唆するものは何もありません (典型的/真の意味で)。何らかのタイプの複雑な検索を行っているようです。メソッドが文書化されていない属性を使用していることに気付き、__DynamicallyInvokableHans によるこの属性の簡単な説明を見つけました ( __DynamicallyInvokable 属性は何のためのものですか? )。

私の質問は次のとおりです。パフォーマンスが重要なコードの場合、十分に高速であることを信頼できますか (文字列をキャッシュしますか? )、またはリソース文字列を自分で前処理してキャッシュする必要がありますか?ResourceManager

御時間ありがとうございます。

4

2 に答える 2

2

メモリに保持されているResourceSetのは、動作している s のようなもので、文字列を直接保持しているように見えます。この時点では、すべての呼び出しがさまざまなリソース名とさまざまなカルチャに対して着信している可能性があるため、このメソッド内に必ずしも表示されるとは限りません。

そして、いつものように、これはあなたのプロファイリングがあなたにパフォーマンスの問題があることを伝えた場所ですか? 非効率な場所を推測してコードを最適化しようとすることは、たとえあったとしてもめったにありません。

于 2013-04-10T14:19:01.333 に答える