Получение значения Enum через отражение - PullRequest
38 голосов
/ 25 августа 2010

У меня есть простой Enum

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

var testing = TestEnum.TestOne;

И я хочу получить его значение (3) с помощью отражения.Есть идеи как это сделать?

Ответы [ 13 ]

47 голосов
/ 14 ноября 2012

Отличный вопрос Матем.

Сценарий вопроса таков:

У вас есть неизвестный тип перечисления и некоторое неизвестное значение этого типа, и вы хотите получить базовое числовое значение этого неизвестного значения.

Это однострочный способ сделать это с помощью отражения:

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

Если значение равно TestEnum.TestTwo, то value.GetType() будет равно typeof(TestEnum), Enum.GetUnderlyingType(value.GetType()) будет равно typeof(int), а значение будет равно 3 (в штучной упаковке; см. http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx для подробнее о значениях для упаковки и распаковки).

Зачем кому-то писать такой код? В моем случае у меня есть подпрограмма, которая копирует значения из модели представления в модель. Я использую это во всех моих обработчиках в проекте ASP.NET MVC как часть очень чистой и элегантной архитектуры для написания обработчиков, у которых нет проблем безопасности, которые создают обработчики, созданные шаблонами Microsoft.

Модель генерируется Entity Framework из базы данных и содержит поле типа int. Модель представления имеет поле некоторого типа enum, назовем его RecordStatus, который я определил в другом месте моего проекта. Я решил полностью поддерживать перечисления в моих рамках. Но теперь существует несоответствие между типом поля в модели и типом соответствующего поля в модели представления. Мой код обнаруживает это и преобразует enum в int, используя код, аналогичный приведенному выше однострочному.

30 голосов
/ 07 октября 2013

Вы можете использовать помощники 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

20 голосов
/ 25 августа 2010

Полный код: Как получить значения Enum с отражением в 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";
}
6 голосов
/ 25 августа 2010

Зачем вам нужно отражение?

int value = (int)TestEnum.TestOne;
2 голосов
/ 22 февраля 2017

Для вашего требования это так же просто, как люди уже указали.Просто приведите объект enum к int, и вы получите числовое значение перечисления.

int value = (int) TestEnum.TestOne;

Однако, если необходимо смешать значения перечисления с |(побитовое ИЛИ), например,

var value = TestEnum.TestOne | TestEnum.TestTwo;

, и вы хотите получить, какие опции представляет смешанное значение, вот как вы можете это сделать (примечание: это для перечислений, представленных значениями int, предназначенными дляпреимущество побитовых операций):

сначала получите параметры enum вместе со своими значениями в словаре.

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

надеюсь, это поможет.

2 голосов
/ 03 июня 2014

Попробуйте следующее:

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)));
1 голос
/ 27 февраля 2015

Привет, у вас есть эта альтернатива:

Type typevar = GetType([YourEnum])

А потом ... ... Вы можете получить имена, используя typevar.GetEnumNames, возвращая массив с именами, и получать значения, используя type.GetEnumValues, возвращая массив со значениями.

1 голос
/ 25 августа 2010

Нет необходимости в отражении:

int value = (int)TestEnum.TestOne;
0 голосов
/ 09 ноября 2018

Должна быть мотивация, чтобы задать такой вопрос.Здесь у меня есть один реальный сценарий с хорошей мотивацией сделать что-то подобное и решение этой проблемы.

Мотивация

2 сборок с круговыми ссылками.Одна ссылка является жесткой ссылкой, то есть тегом <Reference . . .> в файле проекта.И мягкая ссылка в противоположном направлении.assembly1 должен вызывать некоторый объект, некоторый метод в assembly2.Аргумент метода: enum

Вот код, который получит значение 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);

Итог - это действительно полезно, когда одна сборка не знает (и не может знать) других внутренних компонентов сборки.

0 голосов
/ 14 ноября 2016

В моем случае проблема заключалась в том, что MyEnum не был найден из-за получения знака + из типа сборки (строка 2):

var dll = System.Reflection.Assembly.LoadFile("pathToDll");
Type myEnum = dll.GetType("namespace+MyEnum");
System.Array myEnumValues = System.Enum.GetValues(myEnum);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...