C# DataAnnotations:带显示名称的属性模型及相关内容的翻译与技术改写
C# 数据注解:基于字符串列表设置模型属性的显示名称
问题描述
我目前有一个继承自BaseViewData的C#模型类TVSystemViewData,每个属性都通过[Display]特性硬编码了显示名称。同时我手头有一个包含对应属性显示名称的字符串列表,想请教如何通过这个列表来设置模型属性的Display(Name)值,替代当前逐个硬写的方式?
我的模型代码如下:
public class TVSystemViewData : BaseViewData { [Display(Name = "AccountId", Description = "")] public String AccountId { get; set; } [Display(Name = "AllocatedManagedMemory", Description = "")] public String AllocatedManagedMemory { get; set; } [Display(Name = "AllocatedPhysicalMemory", Description = "")] public String AllocatedPhysicalMemory { get; set; } [Display(Name = "AudioMute", Description = "")] public String AudioMute { get; set; } // 其他属性省略... }
解决方案
嘿,这个需求我之前做项目时也碰到过,刚好有几个实用的方案可以分享给你,你可以根据自己的场景来选:
方案一:反射动态修改特性值
DisplayAttribute的Name属性是可写的,所以我们可以通过反射遍历模型的所有属性,找到对应的Display特性,再从字符串列表里匹配对应名称赋值。这种方式是运行时动态修改,只会影响当前应用域内的特性实例,适合需要根据不同环境/配置切换显示名称的场景。
示例代码:
// 假设你的字符串列表用字典存储,键是属性名,值是目标显示名称 var displayNameMap = new Dictionary<string, string> { {"AccountId", "账户ID"}, {"AllocatedManagedMemory", "已分配托管内存"}, {"AllocatedPhysicalMemory", "已分配物理内存"}, {"AudioMute", "音频静音状态"} // 其他属性的对应名称 }; // 获取模型类型 var modelType = typeof(TVSystemViewData); foreach (var property in modelType.GetProperties()) { // 获取属性上的Display特性实例 var displayAttr = property.GetCustomAttribute<DisplayAttribute>(); if (displayAttr != null && displayNameMap.TryGetValue(property.Name, out var newDisplayName)) { // 替换显示名称 displayAttr.Name = newDisplayName; } }
方案二:自定义动态显示特性
如果需要更灵活的全局控制,可以自定义一个继承自DisplayAttribute的特性,让它支持从外部数据源读取显示名称。这种方式扩展性更强,适合需要统一管理显示名称的场景。
首先定义自定义特性:
public class DynamicDisplayAttribute : DisplayAttribute { private readonly string _propertyKey; private static Dictionary<string, string> _displayNameStore; // 静态初始化方法,用来传入你的显示名称列表 public static void Initialize(Dictionary<string, string> displayNameMap) { _displayNameStore = displayNameMap; } public DynamicDisplayAttribute(string propertyKey) { _propertyKey = propertyKey; } public override string Name { get { // 如果找到对应名称就返回,否则返回默认键 if (_displayNameStore != null && _displayNameStore.TryGetValue(_propertyKey, out var displayName)) { return displayName; } return _propertyKey; } } }
然后修改模型类,替换原有[Display]特性:
public class TVSystemViewData : BaseViewData { [DynamicDisplay("AccountId")] public String AccountId { get; set; } [DynamicDisplay("AllocatedManagedMemory")] public String AllocatedManagedMemory { get; set; } [DynamicDisplay("AllocatedPhysicalMemory")] public String AllocatedPhysicalMemory { get; set; } [DynamicDisplay("AudioMute")] public String AudioMute { get; set; } // 其他属性... }
最后在应用启动时初始化特性:
var displayNameMap = new Dictionary<string, string> { {"AccountId", "账户ID"}, // 其他对应项 }; DynamicDisplayAttribute.Initialize(displayNameMap);
方案三:使用资源文件(官方推荐)
如果你的显示名称需要支持多语言或者集中管理,官方最推荐的方式是使用资源文件。这种方式不仅能轻松修改显示名称,还天然支持多语言切换,完全符合.NET的设计规范。
步骤如下:
- 新建一个资源文件(比如
ModelResources.resx),添加键值对:- 键:
AccountId,值:账户ID - 键:
AllocatedManagedMemory,值:已分配托管内存 - 其他属性的键值对以此类推
- 键:
- 修改模型的
Display特性,指定资源类型和资源键:
public class TVSystemViewData : BaseViewData { [Display(Name = nameof(ModelResources.AccountId), ResourceType = typeof(ModelResources))] public String AccountId { get; set; } [Display(Name = nameof(ModelResources.AllocatedManagedMemory), ResourceType = typeof(ModelResources))] public String AllocatedManagedMemory { get; set; } // 其他属性... }
之后只要修改资源文件的内容,就能动态更新模型属性的显示名称,非常方便。
内容的提问来源于stack exchange,提问作者Fabio Santos




