【问题标题】:Getting Enum value via reflection通过反射获取枚举值
【发布时间】:2023-03-31 02:55:01
【问题描述】:

我有一个简单的枚举

 public enum TestEnum
 {
     TestOne = 3,
     TestTwo = 4
 }

var testing = TestEnum.TestOne;

我想通过反射检索它的值 (3)。关于如何做到这一点的任何想法?

【问题讨论】:

  • 致您的 cmets:在任何意义上您“拥有”TestEnum.TestOne 值的上下文中,您已经拥有3 值。你到底有什么?
  • 我看到很多答案在这里指出 (int)TestEnum。如果没有必要,一个人不会要求通过反思来做这件事。依赖注入可能或者我为什么来这里标准库的兼容性以具有仅框架功能。如果有的话。

标签: c# reflection enums


【解决方案1】:

很好的问题。

问题的场景是这样的:

您有一些未知枚举类型和一些该类型的未知值,并且您想要获取该未知值的基础数值 .

这是使用反射的单行方式:

object underlyingValue = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));

如果 value 恰好是 TestEnum.TestTwo,那么 value.GetType() 将等于 typeof(TestEnum)Enum.GetUnderlyingType(value.GetType()) 将等于 typeof(int),并且 value 将是 3(加框;请参阅 http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx 了解更多关于装箱和拆箱值)。

为什么需要编写这样的代码?就我而言,我有一个将值从视图模型复制到模型的例程。我在 ASP.NET MVC 项目中的所有处理程序中都使用它,作为一个非常干净和优雅的架构的一部分,用于编写不存在 Microsoft 模板生成的处理程序存在的安全问题的处理程序。

模型是由实体框架从数据库中生成的,它包含一个 int 类型的字段。 viewmodel 有一个枚举类型的字段,我们称之为 RecordStatus,我在项目的其他地方已经定义了它。我决定在我的框架中完全支持枚举。但是现在模型中的字段类型和视图模型中对应字段的类型不匹配。我的代码检测到这一点,并使用类似于上面给出的单行代码的代码将枚举转换为 int。

【讨论】:

  • 你的回答很好地回答了你问自己的问题,但我不认为这是对这里提出的问题的回答。
  • 感谢您的评论,但实际上这 Mat 所问问题的答案。
  • 更具体地说,Mat 询问他如何使用反射 获取某个简单枚举类型 (TestEnum) 的枚举值(测试)的(基础)值 (3)。 Daniel 和 Fredrik 认为他问错了,并回答说反射是不必要的,Pranay 完全回答了一个不同的问题(如何使用反射列出枚举类型的值)。正是因为当前投票的答案没有解决所提出的问题,所以我改写了它,回答了它,并举了一个例子,说明人们可能想要完全按照 Mat 的要求去做! :-)
  • @hvd:感谢您的评论。我想说传递给 Convert.ChangeType 的第二个参数是一个类型对象(即 System.Type 类型的对象,它是 System.Reflection.MemberInfo 的子类)这一事实意味着即使是转换本身 正在使用 .NET CLR 的反射基础结构!所以,我认为我没有忽略马特问题中的要求,也没有认为他首先添加它是错误的!如果没有这个要求,看起来 Mat 是在追求 Fredrik 和 Daniel 给出的那种答案。
  • 我按原样回答了这个问题,没有试图猜测或怀疑 Mat 表达他想要什么的能力。如果如您所说,他希望能够使用反射从“TestEnum.TestOne”变为 3,而不是从 TestEnum.TestOne 变为 3,那么我同意他的问题没有传达这一点。但就目前而言,这是一个完全合理的问题,现在它有了答案。 :-) @mjmcloug:有 cmets 吗?
【解决方案2】:

您可以使用 System.Enum 助手:

System.Type enumType = typeof(TestEnum);
System.Type enumUnderlyingType = System.Enum.GetUnderlyingType(enumType);
System.Array enumValues = System.Enum.GetValues(enumType);

for (int i=0; i < enumValues.Length; i++)
{
    // Retrieve the value of the ith enum item.
    object value = enumValues.GetValue(i);

    // Convert the value to its underlying type (int, byte, long, ...)
    object underlyingValue = System.Convert.ChangeType(value, enumUnderlyingType);

    System.Console.WriteLine(underlyingValue);
}

输出

3
4

【讨论】:

  • 这是更好的答案。因为我在这里提出了同样的问题,我意识到这是一个 XY 问题。反射不是我需要的。
  • 在转换为 int (.Net 4.5) 时收到此错误“'System.InvalidCastException' 类型的未处理异常”。
  • 并非所有枚举都是整数!枚举也可以是 sbyte、byte、short、ushort、uint、long、ulong 和 char。正如接受的答案所暗示的那样,您应该转换为基础类型。
  • 确实,我相应地更新了我的答案(此时,Miltos 的答案也涵盖了这一点,但我会让我的答案更准确)
  • 这就是我一直在寻找的答案!它对我有用。谢谢:)
【解决方案3】:

完整代码:How to Get Enum Values with Reflection in C#

MemberInfo[] memberInfos = typeof(MyEnum).GetMembers(BindingFlags.Public | BindingFlags.Static);
string alerta = "";
for (int i = 0; i < memberInfos.Length; i++) {
alerta += memberInfos[i].Name + " - ";
alerta += memberInfos[i].GetType().Name + "\n";
}

【讨论】:

  • 我没有-1,但我猜即使答案是正确的,它也不是很具有描述性。这是一个链接和一些代码,弄清楚。它可以通过几种方式变得更好,其中之一是提供示例输出。
【解决方案4】:

为什么需要反思?

int value = (int)TestEnum.TestOne;

【讨论】:

  • ;) 是的,我知道该怎么做。但我需要使用反射
  • 因为我们不知道TestEnum的类型,我们只知道我们有一个枚举。
  • 如果我没有此信息namespace.TestEnum 但只有此"namespace.TestEnum" 怎么办
  • @T.S.你可以使用Type.GetType(yourString) 来获取System.Type
  • 仅当它的已知/引用类型。但是如果它在其他程序集中的某个地方声明呢?
【解决方案5】:

对于您的要求,正如人们已经指出的那样简单。只需将枚举对象转换为 int 即可获得枚举的数值。

int value = (int) TestEnum.TestOne;

但是,如果需要将枚举值与 | (按位或)例如

var value = TestEnum.TestOne | TestEnum.TestTwo;

并且您希望获得混合值表示的选项,这是您可以做到的方法(注意:这是针对旨在利用按位运算的 int 值表示的枚举):

首先,在字典中获取枚举选项及其值。

var all_options_dic = typeof(TestEnum).GetEnumValues().Cast<object>().ToDictionary(k=>k.ToString(), v=>(int) v);

过滤字典以仅返回混合选项。

var filtered = all_options_dic.Where(x => (x.Value & (int) options) != 0).ToDictionary(k=>k.Key, v=>v.Value);

用你的选择做任何逻辑。例如打印它们,将它们转换为列表等:

foreach (var key in filtered.Keys)
        {
            Console.WriteLine(key + " = " + filtered[key]);
        }

希望这会有所帮助。

【讨论】:

    【解决方案6】:

    尝试以下方法:

    System.Array enumValues = System.Enum.GetValues(typeof(MyEnum));
    Type underlyingType = System.Enum.GetUnderlyingType(MyEnum);
    
    foreach (object enumValue in enumValues)
        System.Console.WriteLine(String.Format("{0}",Convert.ChangeType(enumValue ,underlyingType)));
    

    【讨论】:

      【解决方案7】:

      如果您在仅反射上下文中加载了程序集,则 GetValue 和 GetValues 方法不起作用。但我们可以使用另一种方法:

      var val = typeof(MyEnum).GetFields()
          .Where(fi => fi.IsLiteral && fi.Name == "TestOne")
          .Select(fi => fi.GetRawConstantValue())
          .First();
      

      【讨论】:

        【解决方案8】:

        您好,您有这个选择:

        Type typevar = GetType([YourEnum])

        然后... ... 您可以使用typevar.GetEnumNames 获取名称,返回一个包含名称的数组,并使用type.GetEnumValues 获取值,返回一个包含值的数组。

        【讨论】:

          【解决方案9】:

          您可以使用 Gethashkey 函数获取未知类型的枚举值。

          Enum.Parse(enumType, enumvalue).GetHashCode();
          

          更多细节

          动态获取枚举类型

            private static Type GetEnumType(string enumName)
              {
                      foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                      {
                          var type = assembly.GetType(enumName);
                          if (type == null)
                              continue;
                          if (type.IsEnum)
                              return type;
                      }
                  return null;
              }
          

          读取枚举值

          Enum.GetValues(enumType);
          

          希望对大家有所帮助!

          【讨论】:

            【解决方案10】:

            使用此方法通过反射获取枚举 int 值

            protected static object PropertyValue(object obj, string propertyName)
            {
              var property = obj.GetType().GetProperty(propertyName);
              if(property == null)
                throw new Exception($"{propertyName} not found on {obj.GetType().FullName}");
            
              if (property.PropertyType.IsEnum)
                return (int) property.GetValue(obj);
              return property.GetValue(obj);
            }
            

            【讨论】:

              【解决方案11】:

              无需反思:

              int value = (int)TestEnum.TestOne;
              

              【讨论】:

              • 再一次我知道如何做到这一点。但我需要使用反射
              • @mjmcloug:如果您用关于为什么需要使用反射和用例的简要信息来扩展您的问题,您会得到更好的答案:)
              【解决方案12】:
              System.Type.GetType("Namespace Name" + "." + "Class Name" + "+" + "Enum Name")
              
              Dim fieldInfos() As System.Reflection.FieldInfo = System.Type.GetType("YourNameSpaceName.TestClass+TestEnum").GetFields
              
              For Each f As System.Reflection.FieldInfo In fieldInfos 
                  If f.IsLiteral Then 
                      MsgBox(f.Name & " : " & CType(f.GetValue(Nothing), Integer) & vbCrLf) 
                  End If 
              Next 
              
              Public Class TestClass
                  Public Enum TestEnum
                      val1 = 20
                      val2 = 30
                  End Enum
              End Class
              

              有效

              【讨论】:

                【解决方案13】:

                在我的例子中,问题是 MyEnum 未找到,因为 + 号从程序集获取类型(第 2 行):

                var dll = System.Reflection.Assembly.LoadFile("pathToDll");
                Type myEnum = dll.GetType("namespace+MyEnum");
                System.Array myEnumValues = System.Enum.GetValues(myEnum);
                

                【讨论】:

                  【解决方案14】:

                  很简单。

                  var value = propertyInfo.GetValue(obj);  // this return TestOne or TestTwo
                  
                  var enumValue = Convert.ChangeType(value, typeof(int));  // this return 3 or 4 
                  

                  【讨论】:

                    【解决方案15】:

                    或者,如果您需要实际的枚举对象(TestEnum 类型):

                    MemberInfo[] memberInfos = typeof(MyEnum).GetMembers(BindingFlags.Public | BindingFlags.Static);
                    string alerta = "";
                    for (int i = 0; i < memberInfos.Length; i++) {
                    
                    alerta += memberInfos[i].Name + " - ";
                    
                    
                    /* alerta += memberInfos[i].GetType().Name + "\n"; */ 
                    
                    // the actual enum object (of type MyEnum, above code is of type System.Reflection.RuntimeFieldInfo)
                    object enumValue = memberInfos[i].GetValue(0);
                    alerta += enumValue.ToString() + "\n";
                    }
                    

                    【讨论】:

                      【解决方案16】:

                      必须有动机提出这样的问题。在这里,我有一个真实的生活场景,有很好的动机去做这样的事情以及解决这个问题的方法。

                      动机

                      2 个带有循环引用的程序集。一种引用是硬引用,即项目文件中的&lt;Reference . . .&gt; 标记。以及相反方向的软参考。 assembly1 必须调用assembly2 中的某个对象、某个方法。方法的参数是enum

                      这是获取枚举值的代码。调用此方法时程序集已加载,因为包含方法的对象的实例已加载

                      解决方案

                      internal static object GetEnumValue(string assemblyName, string enumName, string valueName) // we know all these 
                      {
                          var assembly = Assembly.Load(assemblyName);
                          var converter = new EnumConverter(assembly.GetType(enumName)); 
                          object enumVal = converter.ConvertFromString(valueName);
                          return enumVal;
                      }
                      

                      及用法

                      dynamic myInstance = GetInstanceOfKnownObject(.......); // this preloads assembly for first time. All sequential loads are easy
                      dynamic enumArg = GetEnumValue("assemblyName", "assembly2.namespace1.EnumName", "enumValueName"); // important to load into 'dynamic', not 'object'
                      myInstance.MyMethod(enumArg);
                      

                      底线 - 当一个程序集不知道(并且无法了解)其他程序集内部时,它非常有用。

                      【讨论】:

                      • 可能是因为像我一样,我不明白这是如何回答这个 8 年前的问题的。
                      • @Rob 不是您不理解的答案,而是问题。人们不断要求检索未知枚举的枚举值,即来自未引用程序集的枚举,这些对象通过反射调用。因此,枚举需要通过反射来检索。 OP 不断重复“我又知道如何做到这一点。但我需要使用反射”。好吧,这个问题不是很清楚,但你能感觉到 OP 在问什么,我知道 OP 来自哪里。这个问题被浏览了 48K 次,所以它是必要的。我的回答解释了如何正确地做到这一点,但也增加了常见的场景
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-05-28
                      • 2011-06-12
                      • 2017-11-07
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多