如何在C# ASP.NET MVC中根据内部标志重写ResourceManager的GetString方法
解决方案
方案1:自定义ResourceManager子类+反射替换(零视图代码修改)
这个方案不需要改动任何现有视图或业务代码,通过替换默认的ResourceManager实例来实现字符串补丁,是侵入性最低的方式。
实现步骤:
- 创建自定义的
PatchedResourceManager类,继承自ResourceManager,重写GetString方法添加替换逻辑:
public class PatchedResourceManager : ResourceManager { private readonly string _targetAnimal; public PatchedResourceManager(Type resourceSource, string targetAnimal) : base(resourceSource) { _targetAnimal = targetAnimal; } public override string GetString(string name) => PatchString(base.GetString(name)); public override string GetString(string name, CultureInfo culture) => PatchString(base.GetString(name, culture), culture); private string PatchString(string original, CultureInfo culture = null) { if (string.IsNullOrEmpty(original)) return original; culture ??= Thread.CurrentThread.CurrentUICulture; // 根据当前语言和目标动物做针对性替换 return culture.Name switch { "en-US" => ReplaceEnglishTerms(original), "zh-CN" => ReplaceChineseTerms(original), // 扩展其他语言的替换规则 _ => original }; } private string ReplaceEnglishTerms(string original) { var lowerAnimal = _targetAnimal.ToLower(); var pluralAnimal = $"{_targetAnimal}s"; return original.Replace("dog", lowerAnimal) .Replace("Dog", _targetAnimal) .Replace("dogs", pluralAnimal); } private string ReplaceChineseTerms(string original) { var chineseAnimal = _targetAnimal switch { "Cat" => "猫咪", "Squirrel" => "松鼠", "Dog" => "狗狗", _ => _targetAnimal }; return original.Replace("狗狗", chineseAnimal); } }
- 在
Global.asax.cs的Application_Start方法中,用反射替换自动生成的Resources类的静态resourceMan字段:
protected void Application_Start() { // 从配置读取当前要切换的目标动物(可根据业务逻辑动态调整,比如从用户设置读取) var targetAnimal = ConfigurationManager.AppSettings["CurrentAnimal"] ?? "Dog"; // 获取Resources类的私有静态resourceMan字段 var resourceType = typeof(Resources); var resourceManField = resourceType.GetField("resourceMan", BindingFlags.Static | BindingFlags.NonPublic); if (resourceManField == null) return; // 实例化自定义ResourceManager并替换原有实例 var patchedManager = new PatchedResourceManager(resourceType, targetAnimal); resourceManField.SetValue(null, patchedManager); }
优点:完全不需要修改现有视图和业务代码,所有资源访问自动经过补丁处理;缺点:依赖反射,需要确保自动生成的Resources类结构不变(通常默认生成的结构稳定)。
方案2:HtmlHelper扩展方法(低侵入性,可控修改)
如果不想用反射,可以通过扩展HtmlHelper的方式,封装资源读取和补丁逻辑,然后批量替换视图中的资源调用。
实现步骤:
- 创建HtmlHelper扩展类:
public static class LocalizationExtensions { public static MvcHtmlString Localized(this HtmlHelper helper, string resourceKey) { var culture = helper.ViewContext.HttpContext.Request.UserLanguages?.FirstOrDefault() ?? Thread.CurrentThread.CurrentUICulture.Name; var original = Resources.ResourceManager.GetString(resourceKey, new CultureInfo(culture)); var patched = PatchString(original, culture); return MvcHtmlString.Create(patched); } private static string PatchString(string original, string cultureName) { var targetAnimal = ConfigurationManager.AppSettings["CurrentAnimal"] ?? "Dog"; if (string.IsNullOrEmpty(original)) return original; return cultureName switch { "en-US" => original.Replace("dog", targetAnimal.ToLower()) .Replace("Dog", targetAnimal) .Replace("dogs", $"{targetAnimal}s"), "zh-CN" => original.Replace("狗狗", targetAnimal switch { "Cat" => "猫咪", "Squirrel" => "松鼠", _ => "狗狗" }), _ => original }; } }
- 批量替换视图中的资源调用:
在Visual Studio中使用查找替换(开启正则表达式),查找模式为@Resources\.(\w+),替换模式为@Html.Localized("$1"),一键完成所有视图的修改。
优点:实现简单,不依赖反射,逻辑清晰;缺点:需要修改所有视图中的资源调用代码(但可通过正则批量替换完成)。
方案3:自定义资源访问包装类(适用于业务代码和视图共用)
如果业务代码中也有大量直接访问Resources的场景,可以封装一个静态包装类,统一处理资源读取和补丁:
public static class LocalizationService { public static string GetString(string resourceKey) { var culture = Thread.CurrentThread.CurrentUICulture; var original = Resources.ResourceManager.GetString(resourceKey, culture); return PatchString(original, culture); } private static string PatchString(string original, CultureInfo culture) { // 替换逻辑同方案1,省略重复代码 } }
然后业务代码中用LocalizationService.GetString("AllDogs")替代Resources.AllDogs,视图中用@LocalizationService.GetString("AllDogs"),同样可以用正则批量替换现有代码。
内容的提问来源于stack exchange,提问作者Sebi O.
相关产品推荐
相关产品推荐

