列挙型の最大値を取得する


147

列挙型の最大値をどのように取得しますか?



1
リフレクション呼び出しを使用するのではなく、コンパイラがこれを処理できると思います。この情報にコンパイル時の方法を使用した答えが私の賛成票を受け取るでしょう。
palswim 2017

回答:


214

Enum.GetValues()は値を順番に返すようですので、次のようなことができます:

// given this enum:
public enum Foo
{
    Fizz = 3, 
    Bar = 1,
    Bang = 2
}

// this gets Fizz
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Last();

編集する

コメントを読みたくない場合は、次のようにしてください。

var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Max();

...これは、列挙値の一部が負の場合に機能します。


3
いいね。「配列の要素は、列挙定数のバイナリ値によってソートされます。」msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
これは本当に些細なことだと思って頭を叩きましたが、エレガントな解決策が与えられました。また、列挙値を取得したい場合は、後でConvert.ToInt32()を使用します。これはグーグルの結果です。
jdelator 2008年

53
LINQを使用する場合は、Max()を使用しないでください。これは、より明確で、「思われる」に依存しないのですか?
Marc Gravell

3
パフォーマンスは向上しますが、列挙型の値が負ではない場合に限ります。
ICR、

4
私もMax()に投票します。enumが負でない場合、Last()は失敗し
ます。

41

私はマットの答えに同意します。最小値と最大値だけが必要な場合は、次のように実行できます。

最大:

Enum.GetValues(typeof(Foo)).Cast<int>().Max();

最小:

Enum.GetValues(typeof(Foo)).Cast<int>().Min();

21

Matt Hamiltonの回答によると、私はそのためのExtensionメソッドを作成することを考えました。

以来ValueType、ジェネリック型パラメータ制約は受け付けていません、私は制限するためのより良い方法が見つかりませんでしたTEnumなく、次のことを。

どんなアイデアでも本当にいただければ幸いです。

PS。VBの暗黙性を無視してください。VBをこのように使用するのが大好きです。それがVBの強みであり、それがVBが大好きな理由です。

Howeva、ここにあります:

C#:

static void Main(string[] args)
{
    MyEnum x = GetMaxValue<MyEnum>(); //In newer versions of C# (7.3+)
    MyEnum y = GetMaxValueOld<MyEnum>();  
}

public static TEnum GetMaxValue<TEnum>()
  where TEnum : Enum
{
     return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max();
}

//When C# version is smaller than 7.3, use this:
public static TEnum GetMaxValueOld<TEnum>()
  where TEnum : IComparable, IConvertible, IFormattable
{
    Type type = typeof(TEnum);

    if (!type.IsSubclassOf(typeof(Enum)))
        throw new
            InvalidCastException
                ("Cannot cast '" + type.FullName + "' to System.Enum.");

    return (TEnum)Enum.ToObject(type, Enum.GetValues(type).Cast<int>().Last());
}



enum MyEnum
{
    ValueOne,
    ValueTwo
}

VB:

Public Function GetMaxValue _
    (Of TEnum As {IComparable, IConvertible, IFormattable})() As TEnum

    Dim type = GetType(TEnum)

    If Not type.IsSubclassOf(GetType([Enum])) Then _
        Throw New InvalidCastException _
            ("Cannot cast '" & type.FullName & "' to System.Enum.")

    Return [Enum].ToObject(type, [Enum].GetValues(type) _
                        .Cast(Of Integer).Last)
End Function

これについては、stackoverflow.com / questions / 79126 /…を参照してください:if(!type.IsEnum)
コンクリート

これは、ValueTypeであることを保証し、Enumに制限しないため、「struct」をwhereに追加することもできます。これは私が使用するものです。where T:struct、IComparable、IFormattable
jdawiz

2
答えを更新できます。C#7.3では、拡張メソッドを実際に実行し、(構造体ではなく)Enumタイプに制限することもできました。
Nordes、2018

ただし、これは拡張メソッドではありません。しかし、優れた実用的な方法です。
Ray

14

これは少し厄介ですが、実際の最大値enumInt32.MaxValue(それがenumから派生したと仮定してint)です。実際にその値を持つメンバーを宣言したかどうかに関係なく、任意のInt32値を任意の値にキャストすることは完全に合法enumです。

法的:

enum SomeEnum
{
    Fizz = 42
}

public static void SomeFunc()
{
    SomeEnum e = (SomeEnum)5;
}

クレイジーな値が提供されたときに、整数変数を返された列挙型に設定すると型の不一致が発生して失敗する場合があったので、代わりにLongを使用するのが最善です(エラーを適切にトラップしない場合)。
AjV Jsy

9

もう一度試した後、私はこの拡張メソッドを得ました:

public static class EnumExtension
{
    public static int Max(this Enum enumType)
    {           
        return Enum.GetValues(enumType.GetType()).Cast<int>().Max();             
    }
}

class Program
{
    enum enum1 { one, two, second, third };
    enum enum2 { s1 = 10, s2 = 8, s3, s4 };
    enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };

    static void Main(string[] args)
    {
        Console.WriteLine(enum1.one.Max());        
    }
}

5

Last関数を使用して最大値を取得できませんでした。「max」関数を使用できます。お気に入り:

 class Program
    {
        enum enum1 { one, two, second, third };
        enum enum2 { s1 = 10, s2 = 8, s3, s4 };
        enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };

        static void Main(string[] args)
        {
            TestMaxEnumValue(typeof(enum1));
            TestMaxEnumValue(typeof(enum2));
            TestMaxEnumValue(typeof(enum3));
        }

        static void TestMaxEnumValue(Type enumType)
        {
            Enum.GetValues(enumType).Cast<Int32>().ToList().ForEach(item =>
                Console.WriteLine(item.ToString()));

            int maxValue = Enum.GetValues(enumType).Cast<int>().Max();     
            Console.WriteLine("The max value of {0} is {1}", enumType.Name, maxValue);
        }
    }

4

マシューJサリバン、C#の同意:

   Enum.GetValues(typeof(MyEnum)).GetUpperBound(0);

なぜ誰もが使いたいと思う理由は本当にわかりません:

   Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last();

...一語一句、意味的に言えば、それほど意味がないように思われますか?(常にさまざまな方法があるのは良いですが、後者の利点はわかりません。)


4
GetUpperBoundを使用すると、カウント(40ではなく4)が返されます:MyEnum {a = 0、b = 10、c = 20、d = 30、e = 40}
alirobe

いいキャッチ、私はそれに気づかなかった。このバージョンは、標準の自動列挙型には適していますが、カスタム値を持つ列挙型には適していません。勝者はハミルトン氏のままだと思います。:)
エンジニア、

Enumにビット単位の値がある場合、GetUpperBoundは適切です。(つまり、1、2、4、8など)。たとえば、単体テストを作成している場合は、Math.Pow(2、Enum.GetValues(typeof(MyEnum))。GetUpperBound(0))のような反復回数の多いループを処理する必要があります。
WEFX 2014

長さ(列挙型の値の数)の何が問題になっていますか?シンプルな方が良いです。(これが元の質問に答えるものではありません。)
Ian Goldby

2

System.Enumの下に列挙型に関する情報を取得するためのメソッドがあります。

したがって、Visual StudioのVB.Netプロジェクトでは、「System.Enum」と入力できます。インテリセンスはあらゆる種類の良さをもたらします。

特に1つのメソッドはSystem.Enum.GetValues()で、列挙値の配列を返します。配列を取得したら、特定の状況に適切なことは何でもできるはずです。

私の場合、列挙値はゼロから始まり、数値をスキップしなかったため、列挙型の最大値を取得するには、配列内の要素の数を知る必要があります。

VB.Netコードスニペット:

'''''''

Enum MattType
  zerothValue         = 0
  firstValue          = 1
  secondValue         = 2
  thirdValue          = 3
End Enum

'''''''

Dim iMax      As Integer

iMax = System.Enum.GetValues(GetType(MattType)).GetUpperBound(0)

MessageBox.Show(iMax.ToString, "Max MattType Enum Value")

'''''''

アレイにギャップがある場合は機能しません。また、要素インデックスはたまたまそのインデックスに格納されている値と等しいため、偶然にしか機能しません。によって返される配列内でGetUpperBound()可能な最大のインデックスを取得しますGetValues()。その配列内に格納されている最大値ではありません。
JensG

2

F#では、列挙型をシーケンスに変換するヘルパー関数を使用します。

type Foo =
    | Fizz  = 3
    | Bang  = 2

// Helper function to convert enum to a sequence. This is also useful for iterating.
// stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values-c
let ToSeq (a : 'A when 'A : enum<'B>) =
    Enum.GetValues(typeof<'A>).Cast<'B>()

// Get the max of Foo
let FooMax = ToSeq (Foo()) |> Seq.max   

実行しています...

>タイプFoo = | フィズ= 3 | バング= 2
> val ToSeq: 'A-> seq <' B> when 'A:enum <' B>
> val FooMax:Foo = Fizz

これwhen 'A : enum<'B>は、コンパイラが定義するために必要ではありませんが、有効な列挙型であっても、ToSeqを使用するためには必要です。


1

すべての状況で使用できるわけではありませんが、最大値を自分で定義することがよくあります。

enum Values {
  one,
  two,
  tree,
  End,
}

for (Values i = 0; i < Values.End; i++) {
  Console.WriteLine(i);
}

var random = new Random();
Console.WriteLine(random.Next((int)Values.End));

もちろん、これは列挙型でカスタム値を使用する場合は機能しませんが、簡単な解決策になる場合があります。


1

列挙型の最小値と最大値が必要なときに、以下を使用しました。列挙型の値自体として、列挙型の最小値に等しい最小値と列挙型の最大値に等しい最大値を設定するだけです。

public enum ChannelMessageTypes : byte
{
    Min                 = 0x80, // Or could be: Min = NoteOff
    NoteOff             = 0x80,
    NoteOn              = 0x90,
    PolyKeyPressure     = 0xA0,
    ControlChange       = 0xB0,
    ProgramChange       = 0xC0,
    ChannelAfterTouch   = 0xD0,
    PitchBend           = 0xE0,
    Max                 = 0xE0  // Or could be: Max = PitchBend
}

// I use it like this to check if a ... is a channel message.
if(... >= ChannelMessageTypes.Min || ... <= ChannelMessages.Max)
{
    Console.WriteLine("Channel message received!");
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.