尝试在现有代码中使用 [Description] 数据注释属性

25 浏览
0 Comments

尝试在现有代码中使用 [Description] 数据注释属性

稍后稍作更新

我试图在使用[Description]数据注解属性时,通过enums来显示友好名称。我搜索了很多,但没有实现任何东西。目前,我有一段代码,可以将enum显示为字符串(使用扩展),但我不喜欢ThisIsAnEnum作为enum名称(这是通过字符串扩展分隔开的),它也禁止我使用更长的名称(我需要保持)例如单选按钮项。我的目标是在单选按钮项中使用更长的描述,而无需编写非常长的enum。扩展/助手可能是正确的方法,但我需要将其“适应”到我正在使用的代码中,这就是我在使用许多现有示例时失败的地方。

我使用的代码是通用的,根据一些逻辑,显示单选按钮列表、复选框列表、下拉列表、选择列表或常规文本框。对于多项列表,使用enum,显示enum名称(在使用字符串扩展之后)。

这是显示枚举的特定代码:

public static IEnumerable GetItemsFromEnum
    (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次,而不是为每个枚举显示不同的描述。希望这样能让问题更明确。

0
0 Comments

问题的原因:使用了[Description]数据注释属性,但是在现有代码中没有正确处理该属性。

解决方法:使用[Display]属性来替代[Description]属性,并对现有代码进行修改以正确处理该属性。

具体代码如下:

public static IEnumerable GetItemsFromEnum(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代码,您的解决方案起作用了,复选框不再被选中,下拉框的默认值变为“选择一个”。谢谢!

0