通过反射获取Enum值

发布于 2024-09-15 14:07:55 字数 180 浏览 4 评论 0原文

我有一个简单的枚举

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

var testing = TestEnum.TestOne;

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

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. Any ideas on how to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

雨落星ぅ辰 2024-09-22 14:07:55

很好的问题,马特。

问题的场景是这样的:

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

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

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

如果 value 恰好是 TestEnum.TestTwo,则 value.GetType() 将等于 typeof (TestEnum)、Enum.GetUnderlyingType(value.GetType()) 将等于 typeof(int) 并且 value 将为 3(盒装;请参阅 < a href="http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx" rel="noreferrer">http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx< /a> 有关装箱和拆箱值的更多详细信息)。

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

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

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

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.

The model is generated by the Entity Framework from the database and it contains a field of type int. The viewmodel has a field of some enum type, let's call it RecordStatus, which I have defined elsewhere in my project. 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. My code detects this and converts the enum to an int using the code similar to the one-liner given above.

月下凄凉 2024-09-22 14:07:55

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

You can use the System.Enum helpers:

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
4

落在眉间の轻吻 2024-09-22 14:07:55

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

Full code : 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";
}
睫毛溺水了 2024-09-22 14:07:55

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

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

If you have loaded an assembly in reflection-only context the methods GetValue and GetValues don't work. But we can use another approach:

var val = typeof(MyEnum).GetFields()
    .Where(fi => fi.IsLiteral && fi.Name == "TestOne")
    .Select(fi => fi.GetRawConstantValue())
    .First();
滥情哥ㄟ 2024-09-22 14:07:55

为什么需要反思?

int value = (int)TestEnum.TestOne;

Why do you need reflection?

int value = (int)TestEnum.TestOne;
预谋 2024-09-22 14:07:55

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

希望这会有所帮助。

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 value = (int) TestEnum.TestOne;

However, if there is a need to mix-down enum values with | (bitwise OR) e.g.

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

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. e.g. printing them, turning them to List, etc..:

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

hope this helps.

醉殇 2024-09-22 14:07:55

请尝试以下操作:

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

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)));
绮筵 2024-09-22 14:07:55

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

我希望它对某人有所帮助!

You can use the Gethashkey function to get the value of enum with an unknown type.

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!

伪心 2024-09-22 14:07:55

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

Get enum int value via reflection using this method

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

  if (property.PropertyType.IsEnum)
    return (int) property.GetValue(obj);
  return property.GetValue(obj);
}
三五鸿雁 2024-09-22 14:07:55

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

Or, if you needed the actual enum object (of type 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";
}
动次打次papapa 2024-09-22 14:07:55

你好,你有这个选择:

Type typevar = GetType([YourEnum])

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

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.

无所的.畏惧 2024-09-22 14:07:55
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

那行得通

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

断爱 2024-09-22 14:07:55

很简单。

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

var enumValue = Convert.ChangeType(value, typeof(int));  // this return 3 or 4 

Just simple.

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

var enumValue = Convert.ChangeType(value, typeof(int));  // this return 3 or 4 
挽手叙旧 2024-09-22 14:07:55

无需反思:

int value = (int)TestEnum.TestOne;

No need for reflection:

int value = (int)TestEnum.TestOne;
自找没趣 2024-09-22 14:07:55

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

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

In my case, the problem was MyEnum not been found due to a + sign getting type from assembly (line 2):

var dll = System.Reflection.Assembly.LoadFile("pathToDll");
Type myEnum = dll.GetType("namespace+MyEnum");
System.Array myEnumValues = System.Enum.GetValues(myEnum);
江湖彼岸 2024-09-22 14:07:55

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

动机

2 个带有循环引用的组件。一种引用是硬引用,即 项目文件中的 标记。以及相反方向的软参考。 assemble1 必须调用 assemble2 中的某个对象、某个方法。方法的参数是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);

底线 - 当一个程序集不知道(并且不能了解)其他装配内部结构。

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. One reference is hard reference, i.e. <Reference . . .> tag in project file. And a soft reference in opposite direction. assembly1 must call some object, some method in assembly2. Method's argument is 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文