代码之家  ›  专栏  ›  技术社区  ›  Nathan Taylor

如何确定枚举值的表示类型?

  •  4
  • Nathan Taylor  · 技术社区  · 15 年前

    考虑以下两个枚举:

    enum MyEnum1 {
        Value1 = 1,
        Value2 = 2,
        Value3 = 3
    }
    
    enum MyEnum2 {
         Value1 = 'a',
         Value2 = 'b',
         Value3 = 'c'
    }
    

    我可以通过显式转换检索这些枚举值所表示的物理值, ((int)MyEnum1.Value2) == 2 ((char)MyEnum2.Value2) == 'b' ,但是如果我想得到char表示或int表示而不首先知道要转换到的类型呢?

    有没有可能在没有强制转换的情况下获取枚举的基础值,或者至少在编程上有可能确定基础值的正确类型?

    4 回复  |  直到 15 年前
        1
  •  12
  •   Jon Skeet    15 年前

    这两个枚举的基本值都是 int . 你只是利用了一个事实,从 char 内景 在第二种情况下。

    例如,如果查看Reflector中的第二个枚举,您将看到如下内容:

    internal enum MyEnum2
    {
        Value1 = 0x61,
        Value2 = 0x62,
        Value3 = 0x63
    }
    

    编辑:如果你想要一个不同的基础类型,你必须指定它,例如。

    public enum Foo : long
    {
    }
    

    byte , sbyte short , ushort , , uint , long ulong 是有效的基础枚举类型。

        2
  •  8
  •   Jordão    15 年前

    byte , sbyte , short ushort , int , uint , long ulong . 以下是指定类型的方式:

    enum MyEnum3 : long {
      Value1 = 5L,
      Value2 = 9L,
      Value3 = long.MaxValue
    }
    

    如果不指定类型,则默认为 .

    很遗憾,你不能指定 char

    [AttributeUsage(AttributeTargets.Enum)]
    public class CharAttribute : Attribute { }
    
    [Char] enum MyEnum2 {
      Value1 = 'a',
      Value2 = 'b',
      Value3 = 'c'
    }
    

    然后上这样的课:

    public static class EnumEx {
      public static Type GetUnderlyingType(Type enumType) {
        if (!enumType.IsEnum) throw new ArgumentException();
        if (enumType.GetCustomAttributes(typeof(CharAttribute), false).Length > 0) {
          return typeof(char);
        }
        return Enum.GetUnderlyingType(enumType);
      }
      public static object ConvertToUnderlyingType(object enumValue) {
        return Convert.ChangeType(enumValue,
          GetUnderlyingType(enumValue.GetType()));
      }
    }
    

    (顺便说一句,方法 Enum.GetUnderlyingType 烧焦 因为语言中不能有字符枚举。)

    这将允许您了解扩展的char enum概念:

    var value3 = EnumEx.ConvertToUnderlyingType(MyEnum2.Value3);
    Console.WriteLine(value3);
    

    c 到控制台。

    以避免转换失败(溢出)。保险箱类型是16位宽(就像 烧焦 )或更少: , , 短的 . 如果枚举中的值可以在不损失精度的情况下转换为16位字符,则其他类型是可以的(就像上面的示例一样)。

    使用默认值( 内景 )作为枚举值的基础类型和char文本(可以隐式转换为 )已经足够好了。

    可以在F#中声明字符枚举:

    namespace Drawing
    
    type Color =
       | Red = 'r'
       | Green = 'g'
       | Blue = 'b'
    

    Console.WriteLine(Enum.GetUnderlyingType(typeof(Color)));
    

    它会打印出来 System.Char .

    但是。。。如果你试图利用它的价值观,C会抱怨的。这是:

    Console.WriteLine(Color.Red.ToString());
    

    给出编译器错误:

    Enum.GetName . 运行时似乎没有准备好处理char枚举。这是该方法的摘录(来自Reflector):

    if (((!type.IsEnum && (type != intType)) && ((type != typeof(short)) && (type != typeof(ushort)))) && (((type != typeof(byte)) && (type != typeof(sbyte))) && (((type != typeof(uint)) && (type != typeof(long))) && (type != typeof(ulong)))))
      {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
      }
    

    所以你真的不应该在F#中创建字符枚举。

        3
  •  1
  •   Bryan    15 年前

    enum只是幕后的int类型。您可以将其更改为long、byte和其他一些,但它们必须是数字。Char在这里工作是因为它可以被改成int。所以,对不起,我认为这是不可能的。

        4
  •  0
  •   Paul Rivera    14 年前

    试试这个,对我有用:

    public static bool IsCharEnum(this Type T)
    {
        var enumType = T.IsNullableEnum() ? Nullable.GetUnderlyingType(T) : T;
        if (!enumType.IsEnum) return false;
        try
        {
            return ((int[])Enum.GetValues(enumType)).All(i => char.IsLetter((char)i));
        }
        catch
        {
            return false;
        }
    }
    
    public static bool IsNullableEnum(this Type T)
    {
        var u = Nullable.GetUnderlyingType(T);
        return (u != null) && u.IsEnum;
    }
    

    if (propValue.GetType().IsCharEnum())
    {
        propValue = ((char)Convert.ToInt32(propValue)).ToString();
    }
    

    当propValue的类型为MyEnum2时,该值将更改为char,并为“a”、“b”或“c”