所有,一会儿(当我匆匆离开时)我问了以下问题Performace Overheads when Using Resource Files (.resx)关于使用资源字符串的性能开销。我得到了一个最高投票的答案,并且答案是正确的。但是,在此之前,我正在本地化消息字符串,这些消息字符串在错误条件下被调用而不是性能关键 - 现在我被要求实现本地化到我们的代码'power-house'(许多性能关键代码,嵌入式循环等)。
有一些时间更详细地研究这个,我注意到调用像
这样的资源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;
}
}
上面的代码中没有任何内容表明它正在“缓存”我的字符串(在典型/最真实的意义上),似乎它正在进行某种类型的复杂查找。我注意到该方法使用了未记录的__DynamicallyInvokable
属性,并且Hans(What is the __DynamicallyInvokable attribute for?)发现了对该属性的讨论。
我的问题是:对于性能关键代码,我可以依赖ResourceManager
足够快(是否缓存我的字符串?),或者我需要预先自己处理和缓存资源字符串?
感谢您的时间。
答案 0 :(得分:4)
缓存资源。如果您通过资源管理器跟随调用堆栈,它是这样的: 1。
[System.Security.SecuritySafeCritical] // auto-generated
public virtual String GetString(String name, CultureInfo culture) {
//...
String value = rs.GetString(name, _ignoreCase);
//...
}
2
public virtual string GetString(string name, bool ignoreCase)
{
object objectInternal = this.GetObjectInternal(name);
//...
}
3
private object GetObjectInternal(string name)
{
//...
Hashtable hashtable = this.Table;
//...
return hashtable[(object) name];
}
所以此时从哈希表中读取值。
一旦访问了ressource文件,就会填充哈希表:
构造
[SecuritySafeCritical]
public ResourceSet(string fileName)
{
this.Reader = (IResourceReader) new ResourceReader(fileName);
this.CommonInit();
this.ReadResources();
}
和ReadResources:
protected virtual void ReadResources()
{
IDictionaryEnumerator enumerator = this.Reader.GetEnumerator();
while (enumerator.MoveNext())
{
object obj = enumerator.Value;
this.Table.Add(enumerator.Key, obj);
}
}
答案 1 :(得分:2)
在内存中保存的东西就像它正在使用的ResourceSet
之类的东西,而那些似乎直接持有字符串。你不一定在这个方法中看到它,因为此时,每个调用都可以进入不同的资源名称和不同的文化。
而且,一如既往,是这个,您的分析告诉您有性能问题吗?如果有的话,尝试通过猜测在可能效率低下的地方优化代码是一个好主意。