繁体   English   中英

通过反射获取枚举值

[英]Getting Enum value via reflection

我有一个简单的枚举

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

var testing = TestEnum.TestOne;

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

好问题垫。

问题的场景是这样的:

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

这是使用反射执行此操作的单行方式:

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 类型的字段。 视图模型有一个枚举类型的字段,我们称之为 RecordStatus,我在我的项目的其他地方定义了它。 我决定在我的框架中完全支持枚举。 但是现在模型中字段的类型和viewmodel中对应字段的类型不匹配。 我的代码检测到这一点,并使用类似于上面给出的单行代码的代码将枚举转换为 int。

您可以使用 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

完整代码:如何在 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";
}

为什么需要反思?

int value = (int)TestEnum.TestOne;

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

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

对于您的要求,它就像人们已经指出的那样简单。 只需将枚举对象转换为 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]);
        }

希望这可以帮助。

请尝试以下操作:

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)));

嗨,你有这个选择:

Type typevar = GetType([YourEnum])

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

就是简单。

var value = propertyInfo.GetValue(obj);  // this return TestOne or TestTwo

var enumValue = Convert.ChangeType(value, typeof(int));  // this return 3 or 4 
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

那个有效

无需反思:

int value = (int)TestEnum.TestOne;

就我而言,问题是由于从程序集(第 2 行)获取类型的 + 符号而未找到 MyEnum:

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

您可以使用 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);

我希望它可以帮助某人!

使用此方法通过反射获取枚举 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);
}

或者,如果您需要实际的枚举对象(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";
}

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

动机

2 个带有循环引用的程序集。 一种引用是硬引用,即<Reference . . .> <Reference . . .> <Reference . . .>项目文件中的标签。 和相反方向的软参考。 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);

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM