如何使ToString()返回描述枚举属性(如果存在)?

时间:2013-02-14 06:27:28

标签: f#

我刚刚在C#上发现了这样的问题,并将一些代码转换为F#,但遗憾的是它仍在返回它的名字。问题是:我的错误在哪里?或者当我想要获得A.B.ToString()

时,是否有其他方法可以使用可选的字符串returnin来获得类似枚举的结构

这是我的尝试:

[<TypeConverter(typedefof<EnumToStringUsingDescription>)>]
type FontVariant =
    | [<Description("small-caps")>] smallCaps = 0

type EnumToStringUsingDescription() =
    inherit TypeConverter()
    override X.CanConvertFrom(context : ITypeDescriptorContext, sourceType : Type) =
        sourceType.Equals(typedefof<Enum>);
    override X.CanConvertTo(context : ITypeDescriptorContext, destinationType : Type) =
        (destinationType.Equals(typedefof<String>));
    override X.ConvertFrom(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj) =
        base.ConvertFrom(context, culture, value);
    override X.ConvertTo(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj, destinationType : Type) =
        if (not <| destinationType.Equals(typedefof<String>)) then
            raise <| new ArgumentException("Can only convert to string.", "destinationType");

        if (not <| value.GetType().BaseType.Equals(typedefof<Enum>)) then
            raise <| new ArgumentException("Can only convert an instance of enum.", "value");

        let name = value.ToString();
        let attrs = 
            value.GetType().GetField(name).GetCustomAttributes(typedefof<DescriptionAttribute>, false);
        if (attrs.Length > 0) then attrs.[0]
        else value

2 个答案:

答案 0 :(得分:5)

这里有几个问题。首先,添加TypeConverter不会影响.ToString()。 其次,您的转换返回属性,而不是属性中的描述。这是一个有效的功能。

let getEnumDescription (value: Enum) =
   let typ = value.GetType()
   let name = value.ToString();
   let attrs = typ.GetField(name).GetCustomAttributes(typedefof<DescriptionAttribute>, false)
   if (attrs.Length > 0) then (attrs.[0] :?> DescriptionAttribute).Description :> obj
   else name :> obj

也就是说,某些库/框架将使用Type转换器(如果可用)。可能看起来像这样。可能你必须实现ConvertFrom / CanConvertFrom,我不确定。

type EnumToStringUsingDescription() =
    inherit TypeConverter()
    override X.CanConvertTo(context : ITypeDescriptorContext, destinationType : Type) = (destinationType.Equals(typedefof<String>))
    override X.ConvertTo(context : ITypeDescriptorContext, culture : System.Globalization.CultureInfo, value : obj, destinationType : Type) =
       let typ = value.GetType()
       if (not <| typ.IsEnum) then raise <| new ArgumentException("Can only convert from enum.", "value");
       if (not <| typ.Equals typeof<string>) then raise <| new ArgumentException("Can only convert to string.", "destinationType");
       getEnumDescription (value :?> Enum)

答案 1 :(得分:5)

正如罗伯特所提到的,因为枚举不能拥有成员,因此你无法覆盖ToString,你可以做这样的事情,作为一种妥协:

type FontVariant =
  | ``small-caps`` = 0

然后,printf按预期工作:

printfn "%A" FontVariant.``small-caps``
> small-caps

此外,约翰建议使用受歧视的联盟是一个很好的建议。它们看起来就像枚举,减去数值:

type FontVariant =
  | SmallCaps
  override this.ToString() =
    match this with
    | SmallCaps -> "small-caps"

使用%O格式(%A将使用反射并打印案例名称。)

printfn "%O" FontVariant.SmallCaps

如果您需要数字值,就像枚举提供的那样,您可以定义属性:

member this.Value =
  match this with
  | SmallCaps -> 0

printfn "%d" FontVariant.SmallCaps.Value