C# - 无法从 ResourceManager 获取字符串(来自附属程序集)

Posted

技术标签:

【中文标题】C# - 无法从 ResourceManager 获取字符串(来自附属程序集)【英文标题】:C# - Cannot getting a string from ResourceManager (from satellite assembly) 【发布时间】:2011-03-09 13:38:31 【问题描述】:

我正在开发一个可本地化的应用程序。在我的“本地”资源文件中,我有默认使用的语言(英语),如果可能,我会加载用户的偏好和文化,并加载翻译成语言的字符串。

所以我做了什么:

private static CultureInfo _culture = CultureInfo.CurrentUICulture;
private static ResourceManager _manager;

private static void ToNeutralCulture()

    while (!_culture.IsNeutralCulture)
    
        _culture = _culture.Parent;
    


private static void LoadCulture()

    ResourceManager manager = Properties.Resources.ResourceManager;

    try
    
        ToNeutralCulture();

        string assembly = Assembly.GetCallingAssembly().GetName().CodeBase;
        string assemblyDir = Path.GetDirectoryName(assembly);
        string assemblyName = Path.GetFileNameWithoutExtension(assembly);
        string resourceFileName = string.Format(CultureInfo.InvariantCulture,
            @"0\1_2.dll",
            assemblyDir,
            assemblyName,
            _culture.Name.ToUpper());

        FileInfo resourceFile = new FileInfo(resourceFileName);
        if (resourceFile.Exists)
        
            Assembly resourceAssembly = Assembly.LoadFrom(resourceFile.FullName);
            string[] manifests = resourceAssembly.GetManifestResourceNames();

            if (manifests.Length == 1)
            
                manager = new ResourceManager(manifests[0], resourceAssembly);
            

            using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
            
                IDictionaryEnumerator dict = reader.GetEnumerator();
                while (dict.MoveNext())
                
                    string key = dict.Key as string;
                    object val = dict.Value;

                    //string mVal = manager.GetString(key);
                
            
        
    
    catch (Exception ex)
    
        Trace.WriteLine(ex.Message);

        Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,
            "Fail to loading culture 0", 
            (_culture == null) ? "--" : _culture.EnglishName));
    

    _manager = manager;

程序集已正确加载,枚举器将显示资源文件中存在的所有资源,除了:

string mVal = manager.GetString(key);

当我取消注释此行时,我有一个 System.Resources.MissingManifestResourceException,有人能告诉我为什么吗?

谢谢!


[编辑]

项目“我的应用程序”

namespace MyApp

    Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
    string[] manifests = resourceAssembly.GetManifestResourceNames();

    if (manifests.Length == 1)
    
        manager = new ResourceManager(manifests[0], resourceAssembly);
    

    // Throws the exception
    manager.GetString("PleaseCallIT", null);

    // Works
    using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
    
        IDictionaryEnumerator dict = reader.GetEnumerator();
        while (dict.MoveNext())
        
            string key = dict.key as string; // PleaseCallIT
            object val = dict.value; // Please call IT.
        
    

项目“MyApp_FR”(Resources.Designer.cs 自动生成的文件)

namespace MyApp.Properties 
    // ...
    internal static string PleaseCallIT 
        get 
            return ResourceManager.GetString("PleaseCallIT", resourceCulture);
        
    

我不明白...

【问题讨论】:

您确定该资源存在于资源程序集中吗? 异常相关的错误信息是什么?以下问题和答案可能会对您有所帮助:***.com/questions/1327692/… 是的,我敢肯定,当我使用 Enumerator 在其中循环时,我会得到我放入卫星资源文件中的所有字符串。 @"Mr. Disappointment" : 已经看了,不行。 @Arnaud:Dang,这个怎么样(我认为它最终归结为命名空间问题):jameswho.blogspot.com/2004/06/… 【参考方案1】:

我找到了原因,希望这对遇到同样情况的人有所帮助。

所以,我查看了 MyApp_FR.dll 生成使用资源文件的代码,它是:

new global::System.Resources.ResourceManager("MyApp_FR.Properties.Resources", typeof(Resources).Assembly);

但是在检索清单文件名时,我得到了:

“MyApp_FR.Properties.Resources.resources”

这个房间里似乎有很多.resource...通过删除它,我可以正常使用我的ResourceManager,一切正常...

最终代码:

Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)

    string manifest = manifests[0].Replace(".resources", string.Empty);
    manager = new ResourceManager(manifest, resourceAssembly);


// Works !
manager.GetString("PleaseCallIT", null);

【讨论】:

我反编译了处理这个问题的 .NET 代码,它在加载之前任意附加了.resources 。甚至从 VS 生成的附属程序集也会失败。所以我认为.NET 处理附属程序集的方式还有改进的余地。感谢您的侦探工作。【参考方案2】:

来自微软支持:

如果您使用存在于附属程序集中的本地化资源,则会出现此问题,该资源是通过使用具有不适当文件名的 .resources 文件创建的。如果您手动创建附属程序集,通常会出现此问题:

试试这个知识库

http://support.microsoft.com/kb/839861

【讨论】:

不是手动创建的文件。我在 VS2k8 中创建了一个新项目,进入“属性”->“资源”->“添加”并将我所有的翻译都放在这里。【参考方案3】:

另一种方法,将以下代码作为测试代码:

string[] resources = 
    System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();

在调试时,检查资源的内容,看看它是否与您使用 ResourceManager 加载的内容相匹配。

特别注意,如果你得到类似“MyAssembly..Resources.resources”的东西,那么你需要显式地将“Resources”添加到 ResourceManager 构造函数中:

    private static readonly ResourceManager stringTable =
 new ResourceManager("MyAssembly.Resources", Assembly.GetExecutingAssembly());

【讨论】:

以上是关于C# - 无法从 ResourceManager 获取字符串(来自附属程序集)的主要内容,如果未能解决你的问题,请参考以下文章

Hadoop Nodemanager 和 Resourcemanager 未启动

无法启动ResourceManager问题,怎么解决

根据字符串从资源中取出对应的资源ResourceManager.GetObject

C#获取资源文件

FlinkFlink Cannot serve slot request, no ResourceManager connected Adding as pending request

C# 转换音频表单资源