【问题标题】:C# Casting with objects to EnumsC# 将对象转换为枚举
【发布时间】:2012-08-12 13:14:50
【问题描述】:

这个问题与泛型方法中的枚举类型有关

给定一个枚举

public enum Crustaceans
{
    Frog = 1,
    Toad = 4
}

我可以简单地创建我的枚举实例

short val = 4;
Crustaceans crusty = (Crustaceans) val;

但是,如果

short val = 4;
object obj = (object) val;
Crustaceans crusty = (Crustaceans)obj;

尝试执行crusty的初始化时抛出运行时异常。

谁能解释为什么会发生这种情况,以及为什么这样做是不合法的。

并不是我真的想这样做,但我在尝试用泛型实现类似的事情时遇到了一个问题,实际上这就是幕后发生的事情。即

public T dosomething<T>(short val) where T : new()
{
    T result = (T)(object) val;
    return result;
}

所以我想要做的是有一个通用函数,它可以与枚举和非枚举一起使用(不是那么关键,但会很好),可以将其设置为一个短值而不会引发异常并实际初始化正确的枚举值。

【问题讨论】:

  • 指出青蛙和蟾蜍不是甲壳类动物会不会有点过分? :)
  • @sweetfa:虽然我指出的问题涉及 int 与 decimal 而不是枚举,但它确实解释了行为(与装箱和拆箱有关)。特别是,接受的答案是指 Eric Lippert 的一篇文章:“Representation and Identity”,其中非常详细地解释了这一点。

标签: c# c#-4.0 enums


【解决方案1】:

这样的事情可能会帮助你:

public T dosomething<T>(object o)
{
   T enumVal= (T)Enum.Parse(typeof(T), o.ToString());
   return enumVal;
}

但这适用于枚举,因为使用Enum.Parse(..)

并像这样使用,例如:

object o = 4;
dosomething<Crustaceans>(o);

这将在 您的 情况下返回 Toad

【讨论】:

  • 这可以通过将代码包围并检查它是枚举还是 int 来解决,例如 if(T is enum)
  • 改进(?)版本:public T dosomething(object o) { var enumType = typeof(T); if (!enumType.IsEnum) throw new ArgumentException("Not an enum");返回 (T)Convert.ChangeType(o, enumType); }
【解决方案2】:

如果将整数类型装箱为对象,正确的转换方法是使用Enum.ToObject 方法:

public T Convert<T>(object o)
{
   T enumVal= (T)Enum.ToObject(typeof(T), o);
   return enumVal;
}

【讨论】:

    【解决方案3】:

    在某些情况下,您不能使用泛型(例如在 WPF 转换器中,当您获得 object 的值时)。 在这种情况下,您不能转换为int,因为枚举类型可能不是int。 这是没有泛型的一般方法。 示例是在 WPF 转换器内部给出的,但里面的代码是通用的:

    using System;
    using System.Windows;
    using System.Windows.Data;
    
    .
    .
    .
    
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var enumType = value.GetType();
        var underlyingType = Enum.GetUnderlyingType(enumType);
        var numericValue = System.Convert.ChangeType(value, underlyingType);
        return numericValue;
    }
    

    【讨论】:

      【解决方案4】:

      默认情况下,枚举数字值的类型 = int。 在您的代码中,您希望将具有短类型的值转换为枚举类型。为此,您必须将短类型设置为您的枚举值。这将起作用:

      public enum Crustaceans : short // <--
      {
          Frog = 1,
          Toad = 4
      }
      
      short  @short = 1;
      object @object = @short;
      
      var @enum = (Crustaceans)@object; // @enum = Crustaceans.Frog   
      

      如果您不想更改默认枚举值类型

      public enum Crustaceans
      {
          Frog = 1,
          Toad = 4
      }
      
      object @object = Crustaceans.Frog;
      
      var @enum = (Crustaceans)@object; // @enum = Crustaceans.Frog
      

      public enum Crustaceans
      {
          Frog = 1,
          Toad = 4
      }
      
      int @integer= 1;
      
      var @enum = (Crustaceans)@integer; // @enum = Crustaceans.Frog
      

      【讨论】:

        【解决方案5】:

        Tigrin 的答案会将枚举的字符串名称转换为枚举 - 这可能是所需的,而 Hazzik 的则不会,这也可能是所需的。但是,如果您想要 Tigrin 答案的功能,以及 Hazzik 答案的效率(Tigrin 的答案需要一个枚举,将其转换为字符串,然后再返回......),这段代码就可以做到:

            public static bool TryParseEnum<EnumType>(object obj, ref EnumType enumType) where EnumType : struct, System.IConvertible
            {
                if (obj != null)
                {
                    try
                    {
                        string str = obj as string;
                        if (str == null)
                        {
                            enumType = (EnumType)Enum.ToObject(typeof(EnumType), obj);
                            return true;
                        }
                        else
                        {
                            str = str.Trim();
                            if (str.Length > 0)//optimization to avoid throwing and catching in frequently occurring case
                            {
                                //if (!int.TryParse(str, out int unused))//ARRRRGGGG!!! Microsoft allows the string "2" to be parsed to the enum, which we never want.  Why would anyone want this???
                                {
                                    enumType = (EnumType)Enum.Parse(typeof(EnumType), str, true);
                                    return true;
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
                return false;
            }
        

        注意注释掉的代码中的代码:Tigrin 的回答和上面的代码,允许整数的“字符串”表示,例如“1”,要转换为枚举。实施者必须决定是否允许这样做。

        【讨论】:

          【解决方案6】:

          你可以使用这个扩展:

          public static T ToEnum<T>(this object obj)
              {
                  var objType = obj.GetType();
                  if (typeof(T).IsEnum)
                  {
                      if (objType == typeof(string))
                          return (T)Enum.Parse(typeof(T), obj.ToString());
                      return (T)Enum.ToObject(typeof(T), obj);
                  }
                  if (objType == typeof(string))
                      return (T)Enum.Parse(Nullable.GetUnderlyingType(typeof(T)), obj.ToString());
                  return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)), obj);
              }
          

          枚举

          公共枚举甲壳类动物 { Frog = 1, Toad = 4 }

          用法

          Crustaceans x = "Toad".ToEnum<Crustaceans>();
          Crustaceans y = 4.ToEnum<Crustaceans>();
          if (x == y) 
          {
              System.Console.WriteLine("Equale");
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-08-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-24
            相关资源
            最近更新 更多