web-dev-qa-db-ja.com

リフレクションを介して列挙値を取得する

単純な列挙型があります

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

var testing = TestEnum.TestOne;

そして、リフレクションを介してその値(3)を取得したいです。これを行う方法に関するアイデアはありますか?

38
mat-mcloughlin

すばらしい質問です。

質問のシナリオは次のとおりです。

いくつかの未知の列挙型といくつかの未知の値があり、その未知の値の基礎となる数値を取得したい。

これは、リフレクションを使用してこれを行う1行の方法です。

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型のフィールドが含まれています。ビューモデルにはいくつかの列挙型のフィールドがあります。それをRecordStatusと呼びましょう。これをプロジェクトの他の場所で定義しました。私のフレームワークで列挙型を完全にサポートすることにしました。しかし、モデルのフィールドのタイプとビューモデルの対応するフィールドのタイプとの間に不一致があります。私のコードはこれを検出し、上記のワンライナーに似たコードを使用して列挙型をintに変換します。

47

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

30
OLP

完全なコード: C#でReflectionを使用して列挙値を取得する方法

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";
}
20
Pranay Rana

なぜ反射が必要なのですか?

int value = (int)TestEnum.TestOne;
7
Daniel A. White

要件については、すでに指摘されているように簡単です。 enumオブジェクトをintにキャストするだけで、enumの数値を取得できます。

int value = (int) TestEnum.TestOne;

ただし、enum値を|とミックスダウンする必要がある場合(ビットごとのOR)例:.

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

お役に立てれば。

2
H7O

以下を試してください:

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

反射の必要はありません:

int value = (int)TestEnum.TestOne;
1
Fredrik Mörk

こんにちは、この代替手段があります:

Type typevar = GetType([YourEnum])

そして... ...名前付きの配列を返すtypevar.GetEnumNamesを使用して名前を取得し、値付きの配列を返すtype.GetEnumValuesを使用して値を取得できます。

1
dmr

私の場合、問題はアセンブリからタイプを取得する+記号のためにMyEnumが見つからないことでした(2行目):

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

単純な。

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

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