尝试在现有代码中使用 [Description] 数据注释属性
尝试在现有代码中使用 [Description] 数据注释属性
稍后稍作更新
我试图在使用[Description]
数据注解属性时,通过enums
来显示友好名称。我搜索了很多,但没有实现任何东西。目前,我有一段代码,可以将enum
显示为字符串(使用扩展),但我不喜欢ThisIsAnEnum
作为enum
名称(这是通过字符串扩展分隔开的),它也禁止我使用更长的名称(我需要保持)例如单选按钮项。我的目标是在单选按钮项中使用更长的描述,而无需编写非常长的enum
。扩展/助手可能是正确的方法,但我需要将其“适应”到我正在使用的代码中,这就是我在使用许多现有示例时失败的地方。
我使用的代码是通用的,根据一些逻辑,显示单选按钮列表、复选框列表、下拉列表、选择列表或常规文本框。对于多项列表,使用enum
,显示enum
名称(在使用字符串扩展之后)。
这是显示枚举的特定代码:
public static IEnumerableGetItemsFromEnum (T selectedValue = default(T)) where T : struct { return from name in Enum.GetNames(typeof(T)) let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true)) select new SelectListItem { Text = name.ProperCase(), Value = enumValue, Selected = enumValue.Equals(selectedValue) }; }
ProperCase
是将enum
更改为可读内容的类。
我找到了一个几乎可以工作的解决方法:
public static string GetEnumDescription(TEnum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); if ((attributes != null) && (attributes.Length > 0)) return attributes[0].Description; else return value.ToString(); }
在这种情况下,我将代码从Text = name.ProperCase(),
更改为Text = name.GetEnumDescription(...)
,但是如果我将value
放在括号中,我会收到“不存在于当前上下文中”的消息(我尝试修复它,但问题只变得更糟)如果我将其留空,我会得到“没有重载...接受0个参数”(再次,可以理解-但我不知道如何修复)。如果我将name
放在括号中,代码将编译,但在查看页面时,我会在此行上收到“对象引用未设置...”错误:
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes (typeof(DescriptionAttribute), false);
我在这上面花了很多时间,知道我的绊脚石是
Text = name.ProperCase(),
代码。有什么想法/帮助吗?提前感谢。
更新:
如果我这样做:
Text = GetEnumDescription(selectedValue),
我实际上确实获得了[Description]
文本,但是它只显示给第一个枚举。因此,如果我有5个具有不同[Description]
的枚举,该代码只会重复第一个枚举的[Description]
5次,而不是为每个枚举显示不同的描述。希望这样能让问题更明确。
问题的原因:使用了[Description]数据注释属性,但是在现有代码中没有正确处理该属性。
解决方法:使用[Display]属性来替代[Description]属性,并对现有代码进行修改以正确处理该属性。
具体代码如下:
public static IEnumerableGetItemsFromEnum (T selectedValue = default(T)) where T : struct { return from name in Enum.GetNames(typeof(T)) let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true)) select new SelectListItem { Text = GetEnumDescription(name, typeof(T)), Value = enumValue, Selected = name == selectedValue.ToString() }; } public static string GetEnumDescription(string value, Type enumType) { var fi = enumType.GetField(value.ToString()); var display = fi .GetCustomAttributes(typeof(DisplayAttribute), false) .OfType () .FirstOrDefault(); if (display != null) { return display.Name; } return value; }
然后在枚举中使用[Display]属性来定义每个值的描述,如:
public enum Foo { [Display(Name = "value 1")] Value1, Value2, [Display(Name = "value 3")] Value3 }
现在可以通过以下代码来获取枚举的描述列表:
var foo = Foo.Value2; var values = GetItemsFromEnum(foo);
另外需要注意的是,我修改了LINQ表达式中的Selected子句,因为原始代码中的语法是不正确的。
总结起来,我个人建议在视图模型中尽量避免使用枚举,因为它们与内置的ASP.NET MVC不兼容,您将不得不重新实现大部分功能。
感谢Darin的建议,现在显示每个项的属性已经起作用了。不过,FirstOrDefault()这一行导致下拉框跳过了“选择一个”的文本,对于复选框来说,它会自动选中第一项(在我的场景中不是首选项)。有没有办法解决这个问题呢?谢谢。
如果想要为选择框设置默认值,可以尝试使用可为空的枚举类型。
非常抱歉,我不太理解您的意思。我已经在代码中使用了类似`public Foo? FooDropDown { get; set; }`的写法来定义一个可空的枚举,但是我不知道如何将枚举设置为null。能否请您给出一个使用上述代码的示例呢?谢谢。
问题已解决:我保留了原来的Selected代码,您的解决方案起作用了,复选框不再被选中,下拉框的默认值变为“选择一个”。谢谢!