System.Enumから基本整数に変換する方法は?


93

キャストせずに、できれば文字列を解析せずに、任意のSystem.Enum派生型を対応する整数値に変換する汎用メソッドを作成したいと思います。

たとえば、私が欲しいのはこのようなものです:

// Trivial example, not actually what I'm doing.
class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        (int)anEnum;
    }
}

しかし、これは機能していないようです。Resharperは、タイプ 'System.Enum'の式をタイプ 'int'にキャストできないと報告しています。

今、私はこの解決策を思いついたが、もっと効率的なものが欲しい。

class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        return int.Parse(anEnum.ToString("d"));
    }
}

助言がありますか?


1
文句を言うのは、Resharperではなくコンパイラだと思います。
Kugel

1
必ずしも。System.Enumに拡張メソッドがあり、Resharperが不平を言うことがあります:疑いもなく列挙型である場合、インスタンス引数の型 'Some.Cool.Type.That.Is.An.Enum'を 'System.Enum'に変換できません。コードをコンパイルして実行すると、問題なく動作します。次にVSをシャットダウンし、Resharperキャッシュを吹き飛ばして再起動すると、再スキャンが完了すると問題なく動作します。私にとってそれはある種のキャッシュsnafuです。彼にとっても同じかもしれません。
Mir

@ミール私もこれについてReSharperに「不満」を言ってきました。私にとっても同じ修正。これらの型が混同される理由はわかりませんが、コンパイラではありません。
akousmata 2015年

回答:


134

キャストしたくない場合は、

Convert.ToInt32()

トリックを行うことができます。

(を介した(int)enumValue)直接キャストはできません。列挙型が異なる基礎となる型を持つことができるので、これはまた、「危険な」されることに注意してください(intlongbyte...)。

より形式的に:(両方ともsですが)System.Enumと直接の継承関係がないため、型システム内で明示的なキャストを正しく行うことはできませんInt32ValueType


2
Converter.ToInteger(MyEnum.MyEnumConstant);ここではエラーは発生しません。その部分を編集してください。
nawfal 2013

ありがとう、@ nawfal、あなたは正しい。私は応答を編集しました(そして新しいことを学びました:) ...)
MartinStettner

基になるタイプが異なる場合は機能しませんint
Alex Zhukovskiy

@YaroslavSivakovそれは例えばlong列挙型では機能しません。
Alex Zhukovskiy

System.Enumクラスなので、参照型です。値はおそらくボックス化されています。
Teejay

42

オブジェクトにキャストしてからintにキャストすることで機能します。

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return (int)((object)enumValue);
    }
}

これは醜く、おそらく最善の方法ではありません。私はそれをいじり続け、もっと良いものを思いつくことができるかどうかを確認します...

編集:Convert.ToInt32(enumValue)も同様に機能することを投稿しようとしていましたが、MartinStettnerが私を倒したことに気づきました。

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

テスト:

int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday

編集2:コメントの中で、これはC#3.0でのみ機能すると述べています。これをVS2005で次のようにテストしたところ、うまくいきました。

public static class Helpers
{
    public static int ToInt(Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

    static void Main(string[] args)
    {
        Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
    }

+1しましたが、このソリューションはC#3.0以降でのみ機能します。
Vadim、

これはコンパイラーを満足させるだけだと思います。これを実行時にテストできましたか?この関数に値を渡すことができませんでした...
MartinStettner 2009年

拡張メソッドだから?または、古いバージョンのC#の列挙型について何か違いがありますか?
BFree、2009年

投稿の最後にテストを追加しました。私はそれを試しました、そしてそれは私のために働きました。
BFree 2009年

@BFree:拡張メソッドでのみ機能するようです。「古いスタイルの」関数(C#2.0)で試してみましたが、実際に値を渡す構文を見つけることができませんでした(これは、以前のコメントの内容です)
MartinStettner

14

あなたが変換する必要がある場合は任意の(すべての列挙型がが付いていないその基礎となる型に列挙型をint)あなたが使用することができます。

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));

5
これが唯一の完全な答えです。
Rudey

これはボクシングのアンボクシングの原因ですか?
b.ben 2018

@ b.benはい。最初の引数をConvert.ChangeType受け入れobject、を返しますobject
Drew Noakes、2018

ええ、私は実際にこれについて@Rudeyに同意します。とにかく、パフォーマンステストを実行する必要があります。BFreeのソリューションは断然最速です。約8倍速くなります。とにかく、まだダニについて話している。
二十

10

なぜヘルパーメソッドでホイールを再発明する必要があるのですか?enum基になる型に値をキャストすることは完全に合法です。

それはタイピングが少なく、私の意見ではより読みやすいです...

int x = (int)DayOfWeek.Tuesday;

...のようなものではなく...

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();

6
任意の列挙値を変換したい。つまり、いくつかのコードによって一般的な方法で処理されている列挙フィールドを持つさまざまなクラスがあります。これが、intへの単純なキャストが適切でない理由です。
09年

@orj、私はあなたが何を意味するのか本当にわかりません。必要な使用法を示す例を挙げられますか?
LukeH 2009年

2
ジェネリックメソッドの場合など、列挙型を直接キャストできない場合があります。ジェネリックメソッドは列挙型に制約できないため、構造体のようなものに制約しているため、intにキャストできません。その場合は、Convert.ToInt32(enum)を使用して実行できます。
ダニエルT.10年

拡張メソッドToInteger()がToString()と同じフォーマットに従うという考えが気に入っています。int値が必要なときにintにキャストし、文字列値が必要な場合、特にコードが並んでいる場合にToString()を使用する方が読みにくいと思います。
Louise Eggleton 2018年

また、拡張メソッドを使用すると、コードベースに一貫性を追加できます。@nawfalが指摘したように、列挙型からint値を取得するにはいくつかの方法があるため、拡張メソッドを作成してその使用を強制すると、列挙型のint値を取得するたびに同じメソッドを使用することになります。
Louise Eggleton 2018年

4

私の答えからここに

次のように与えられeます:

Enum e = Question.Role;

次に、これらの作業:

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

最後の2つは醜いです。最初の方が読みやすいはずですが、2番目の方がはるかに高速です。または、拡張メソッドは、両方の世界で最高、最高です。

public static int GetIntValue(this Enum e)
{
    return e.GetValue<int>();
}

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    return (T)(object)e;
}

今すぐ呼び出すことができます:

e.GetValue<int>(); //or
e.GetIntValue();

2番目の方が速いですか?私はそれが列挙型をボックス化し、次にボックス化してintに戻すと思いますか?
ヨーヨー、2014

1
@yoyo e変数には、実際の値タイプ、つまり列挙型のボックス化されたインスタンスがすでにあります。あなたが書くとき、Enum e = Question.Role;それはすでに箱に入れられています。問題は、ボックス化System.Enumされたint型(ボックス化解除)に戻すことです。したがって、ここでの開梱はパフォーマンスの問題のみです。(int)(object)eunboxの直接呼び出しです。はい、他のアプローチよりも高速でなければなりません。これを見る
nawfal 14

説明ありがとう。System.Enumのインスタンスがボックス化されていない値であるという誤った印象を受けました。こちらもご覧ください-msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx
yoyo 14

@yoyoうーんはい。リンクからの関連する引用:列挙型からSystem.Enum型へ。
nawfal 2014

1

a System.Enumからint作品へのキャストは私にとってはうまくいきます(MSDNにもあります)。おそらくそれはResharperのバグでしょう。


1
使用しているランタイムのバージョンは何ですか?
JoshBerke 2009年

2
リンクはそれ自体でSystem.Enumはなく、のサブタイプのキャストを示していSystem.Enumます。
nawfal 2013

私が持っていた同様の問題は、Resharperキャッシュsnafuでした。VSを閉じてResharperキャッシュを削除すると、完全に再スキャンした後でもエラーが消えます。
Mir

1

Enumは、byte、sbyte、short、ushort、int、uint、long、ulongに制限されているため、いくつかの仮定を行うことができます。

利用可能な最大のコンテナを使用することで、変換中の例外を回避できます。残念ながら、ulongは負の数に対して爆発し、longはlong.MaxValueとulong.MaxValueの間の数に対して爆発するため、どのコンテナを使用するかは明確ではありません。基になるタイプに基づいて、これらの選択を切り替える必要があります。

もちろん、結果がintに収まらない場合はどうするかを決める必要があります。キャスティングは大丈夫だと思いますが、まだいくつかの落とし穴があります:

  1. int(longおよびulong)よりも大きいフィールドスペースを持つ型に基づく列挙型の場合、一部の列挙型が同じ値に評価される可能性があります。
  2. チェック領域にいる場合、int.MaxValueより大きい数値をキャストすると例外がスローされます。

ここに私の提案があります。この関数をどこに公開するかを決めるのは読者に任せます。ヘルパーまたは拡張として。

public int ToInt(Enum e)
{
  unchecked
  {
    if (e.GetTypeCode() == TypeCode.UInt64)
      return (int)Convert.ToUInt64(e);
    else
      return (int)Convert.ToInt64(e);
  }
}

-1

Enum型自体には静的ヘルパー関数がたくさん含まれていることを忘れないでください。列挙型のインスタンスを対応する整数型に変換するだけの場合は、おそらくキャストが最も効率的な方法です。

Enumは特定の型の列挙ではなく、列挙自体はEnumではなくスカラー値型から派生しているため、ReSharperは不満を持っていると思います。汎用的な方法で適応可能なキャストが必要な場合は、これでうまくいくと思います(列挙型自体もジェネリックに含まれていることに注意してください:

public static EnumHelpers
{
    public static T Convert<T, E>(E enumValue)
    {
        return (T)enumValue;
    }
}

これは次のように使用できます:

public enum StopLight: int
{
    Red = 1,
    Yellow = 2,
    Green = 3
}

// ...

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);

確かに頭から言うことはできませんが、上記のコードはC#の型推論でサポートされているため、次のことが可能です。

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);

1
残念ながら、あなたの例では、Eはどのタイプでもかまいません。ジェネリックスでは、Enumを型パラメーターの制約として使用できません。私は言うことはできません:ここでT:Enum
Vadim

ただし、T:構造体を使用できます。それはあなたが望むほど厳密ではありませんが、参照タイプを切り捨てます(私があなたがしようとしていることだと思います。)
jrista '26

使用できます:if(!typeof(E).IsEnum)throw new ArgumentException( "E must be a enumulated type");
diadiora

1
これはリモートでさえ正しくなく、静的ヘルパーは有効ではありません。
ニコライ2013年

1
なぜEnumHelpers.Convert<int, StopLight>(StopLight.Red);代わりに誰かが使うべき(int)StopLight.Read;ですか?また、問題はについて話しているSystem.Enum
nawfal 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.