简体   繁体   English

通过反射获取枚举值

[英]Getting Enum value via reflection

I have a simple Enum我有一个简单的枚举

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

var testing = TestEnum.TestOne;

And I want to retrieve its value (3) via reflection.我想通过反射检索它的值 (3)。 Any ideas on how to do this?关于如何做到这一点的任何想法?

Great question Mat.好问题垫。

The scenario of the question is this:问题的场景是这样的:

You have some unknown enum type and some unknown value of that type and you want to get the underlying numeric value of that unknown value.您有一些未知的枚举类型和该类型的一些未知值,并且您想要获得该未知值的基础数值

This is the one-line way of doing this using reflection:这是使用反射执行此操作的单行方式:

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

If value happens to be TestEnum.TestTwo , then value.GetType() would be equal to typeof(TestEnum) , Enum.GetUnderlyingType(value.GetType()) would be equal to typeof(int) and value would be 3 (boxed; see http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx for more details about boxing and unboxing values).如果 value 恰好是TestEnum.TestTwo ,则value.GetType()将等于typeof(TestEnum)Enum.GetUnderlyingType(value.GetType())将等于typeof(int)并且 value 将是 3(装箱;有关装箱和拆箱值的更多详细信息,请参阅http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx )。

Why would one ever need to write such code?为什么需要编写这样的代码? In my case, I have a routine that copies values from a viewmodel to a model.就我而言,我有一个将值从视图模型复制到模型的例程。 I use this in all my handlers in an ASP.NET MVC project as part of a very clean and elegant architecture for writing handlers that do not have the security problems the handlers generated by the Microsoft templates do.我在 ASP.NET MVC 项目中的所有处理程序中都使用它作为编写处理程序的非常干净和优雅的体系结构的一部分,这些处理程序没有 Microsoft 模板生成的处理程序会出现的安全问题。

The model is generated by the Entity Framework from the database and it contains a field of type int.该模型由实体框架从数据库生成,它包含一个 int 类型的字段。 The viewmodel has a field of some enum type, let's call it RecordStatus, which I have defined elsewhere in my project.视图模型有一个枚举类型的字段,我们称之为 RecordStatus,我在我的项目的其他地方定义了它。 I decided to support enums fully in my framework.我决定在我的框架中完全支持枚举。 But now there is a mismatch between the type of the field in the model and the type of the corresponding field in the viewmodel.但是现在模型中字段的类型和viewmodel中对应字段的类型不匹配。 My code detects this and converts the enum to an int using the code similar to the one-liner given above.我的代码检测到这一点,并使用类似于上面给出的单行代码的代码将枚举转换为 int。

You can use the System.Enum helpers:您可以使用 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);
}

Outputs输出

3 3
4 4

Full code :How to Get Enum Values with Reflection in C#完整代码:如何在 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;

If you have loaded an assembly in reflection-only context the methods GetValue and GetValues don't work.如果您在仅反射上下文中加载程序集,则 GetValue 和 GetValues 方法将不起作用。 But we can use another approach:但是我们可以使用另一种方法:

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

For your requirement it's as simple as people already pointed it out.对于您的要求,它就像人们已经指出的那样简单。 Just cast the enum object to int and you'd get the numeric value of the enum.只需将枚举对象转换为 int 即可获得枚举的数值。

int value = (int) TestEnum.TestOne;

However, if there is a need to mix-down enum values with |但是,如果需要将枚举值与 | 混合使用(bitwise OR) eg (按位或)例如

var value = TestEnum.TestOne | TestEnum.TestTwo;

and you wish to get what options that mixed-down value represents, here is how you could do it (note: this is for enums that represented by int values intended to take advantage of bitwise operatations) :并且您希望获得混合值代表的选项,这里是您可以这样做的方法(注意:这适用于由旨在利用按位运算的 int 值表示的枚举):

first, get the enum options along with their values in a dictionary.首先,在字典中获取枚举选项及其值。

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

Filter the dictionary to return only the mixed-down options.过滤字典以仅返回混合选项。

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

do whatever logic with your options.用你的选择做任何逻辑。 eg printing them, turning them to List, etc..:例如打印它们,将它们转换为列表等:

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

hope this helps.希望这可以帮助。

Try the following:请尝试以下操作:

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

Hi you have this alternative:嗨,你有这个选择:

Type typevar = GetType([YourEnum])

And then ... ... You can get names using typevar.GetEnumNames returning a array with names and to get values using type.GetEnumValues , returning an array with values.然后……您可以使用typevar.GetEnumNames获取名称,返回一个带有名称的数组,并使用type.GetEnumValues获取值,返回一个带有值的数组。

Just simple.就是简单。

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

That works那个有效

无需反思:

int value = (int)TestEnum.TestOne;

In my case, the problem was MyEnum not been found due to a + sign getting type from assembly (line 2):就我而言,问题是由于从程序集(第 2 行)获取类型的 + 符号而未找到 MyEnum:

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

You can use the Gethashkey function to get the value of enum with an unknown type.您可以使用 Gethashkey 函数获取未知类型的枚举值。

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

More details更多细节

Getting enum type dynamically动态获取枚举类型

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

Reading enum values读取枚举值

Enum.GetValues(enumType);

I hope it helps someone!我希望它可以帮助某人!

Get enum int value via reflection using this method使用此方法通过反射获取枚举 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);
}

Or, if you needed the actual enum object (of type TestEnum) :或者,如果您需要实际的枚举对象(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";
}

There must be a motivation to ask a question like this.提出这样的问题一定是有动机的。 Here I have one real life scenario with good motivation to do something like this and the solution to this problem.在这里,我有一个真实的场景,有很好的动力去做这样的事情以及解决这个问题的方法。

Motivation动机

2 assemblies with circular references. 2 个带有循环引用的程序集。 One reference is hard reference, ie <Reference . . .>一种引用是硬引用,即<Reference . . .> <Reference . . .> <Reference . . .> tag in project file. <Reference . . .>项目文件中的标签。 And a soft reference in opposite direction.和相反方向的软参考。 assembly1 must call some object, some method in assembly2 . assembly1必须调用某个对象,在一些方法assembly2 Method's argument is enum方法的参数是enum

Here is the code that will get enum value.这是将获得枚举值的代码。 The assembly is already loaded at the time of calling this method because instance of the object containing method already loaded在调用此方法时程序集已经加载,因为包含方法的对象的实例已经加载

Solution解决方案

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

And the usage和用法

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

Bottom line - it is really useful when one assembly has no idea (and can't have knowledge) of the other assembly internals.底线 - 当一个程序集不知道(并且无法了解)其他程序集内部结构时,它真的很有用。

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

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