Bir numaralamanın maksimum değerini alma


Yanıtlar:


221

Enum.GetValues ​​() değerleri sırayla döndürüyor gibi görünüyor, bu nedenle şöyle bir şey yapabilirsiniz:

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

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

Düzenle

Yorumları okumak istemeyenler için: Bunu şu şekilde de yapabilirsiniz:

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

... bu, enum değerlerinden bazıları negatif olduğunda işe yarar.


3
Güzel. yararlanarak: "Dizinin öğeleri, numaralandırma sabitlerinin ikili değerlerine göre sıralanır." dan msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
TheSoftwareJedi

2
Bunun gerçekten önemsiz olduğunu düşünerek kafama vuruyordum ama zarif bir çözüm verildi. Ayrıca, enum değerini almak istiyorsanız daha sonra Convert.ToInt32 () öğesini kullanın. Bu, google sonuçları içindir.
jdelator

55
LINQ kullanacaksanız, neden çok daha net olan ve "görünüyor" a güvenmeyen Max () kullanmıyorsunuz?
Marc Gravell

3
Daha iyi performans gösterir, ancak yalnızca numaralandırmanın değerleri negatif değilse, bu olabilirler.
ICR

4
Max () için de oy veriyorum. Enum negatif değilse Last () başarısız olur, buraya
AZ.

41

Matt'in cevabına katılıyorum. Yalnızca minimum ve maksimum int değerlerine ihtiyacınız varsa, bunu aşağıdaki gibi yapabilirsiniz.

Maksimum:

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

Minimum:

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

21

Matt Hamilton'ın cevabına göre, bunun için bir Uzatma yöntemi oluşturmayı düşündüm.

Yana ValueTypebir genel tür parametre kısıtlaması olarak kabul edilmez, ben kısıtlamak için daha iyi bir yol bulamadık Tiçin EnumAşağdakiler.

Herhangi bir fikir gerçekten takdir edilecektir.

PS. lütfen benim VB örtüklüğümü görmezden gelin, VB'yi bu şekilde kullanmayı seviyorum, bu VB'nin gücü ve bu yüzden VB'yi seviyorum.

Howeva, işte burada:

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

Bunun için stackoverflow.com/questions/79126/… adresini ziyaret edin: if (! Type.IsEnum)
Concrete Gannet

Ayrıca, bir ValueType olmasını sağlayacak ancak onu Enum ile sınırlamayacağından "struct" ı da ekleyebilirsiniz.
Kullandığım

2
Cevabınızı güncelleyebilirsiniz. C # 7.3'te aslında uzantı yöntemini yapabilir ve ayrıca Enum türüne (yapı yerine) kısıtlayabilirsiniz.
Nordes

Yine de bu bir uzatma yöntemi değil . Ama iyi bir fayda yöntemi.
Ray

13

Bu biraz titizdir, ancak herhangi enumbirinin gerçek maksimum değeri Int32.MaxValue(bunun enumtüretildiği varsayılarak int). Bu Int32değere enumsahip bir üye ilan edip etmediğine bakılmaksızın herhangi bir değeri herhangi bir değere dönüştürmek tamamen yasaldır .

Yasal:

enum SomeEnum
{
    Fizz = 42
}

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

Çılgın bir değer sağlandığında, bir Tamsayı değişkeninin döndürülen bir numaralandırmaya ayarlanmasının tür uyuşmazlığı ile başarısız olduğu durumlar yaşadım, bu nedenle bunun yerine Uzun kullanmak en iyisidir (eğer hatayı doğru bir şekilde yakalamıyorsanız!).
AjV Jsy

10

Başka bir zaman denedikten sonra, bu uzatma yöntemini aldım:

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

Son işlevi kullanın, maksimum değeri alamadı. "Max" işlevini kullanabilir. Sevmek:

 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

Matthew J Sullivan ile uyumlu olarak, C # için:

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

Gerçekten neden birinin kullanmak isteyeceğinden emin değilim:

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

... Kelime kelime, anlamsal olarak konuşulduğunda, o kadar mantıklı görünmüyor mu? (farklı yollara sahip olmak her zaman iyidir, ancak ikincisinde faydasını görmüyorum.)


4
GetUpperBound kullanmak benim için bir sayı (4, 40 değil) döndürür: MyEnum {a = 0, b = 10, c = 20, d = 30, e = 40}
alirobe

Güzel yakalayış, bunu fark etmemiştim. Tamam, bu nedenle bu sürüm standart otomatik numaralandırmalar için harika, ancak özel değerlere sahip numaralandırmalar için değil. Galiba kazanan Bay Hamilton olarak kalacak. :)
Engineer

Enum'unuz bitsel değerlere sahip olduğunda GetUpperBound iyidir. (yani - 1, 2, 4, 8, vb.). Örneğin, bir birim testi yazıyor olsaydınız, şu kadar çok yinelemeyle bir döngü üzerinden çalışmak istersiniz: Math.Pow (2, Enum.GetValues ​​(typeof (MyEnum)). GetUpperBound (0)).
WEFX

Uzunluk ile ilgili sorun nedir (enum'daki değerlerin sayısı için)? Daha basit, daha iyidir. (Bu, asıl soruyu yanıtladığından değil.)
Ian Goldby

2

System.Enum altında numaralandırılmış türler hakkında bilgi almak için yöntemler vardır.

Yani, Visual Studio'daki bir VB.Net projesinde "System.Enum" yazabilirim. ve zeka her türden iyiliği ortaya çıkarır.

Özellikle bir yöntem, numaralandırılmış değerlerin bir dizisini döndüren System.Enum.GetValues ​​() yöntemidir. Diziyi aldıktan sonra, özel koşullarınıza uygun olanı yapabilmelisiniz.

Benim durumumda, numaralandırılmış değerlerim sıfırdan başladı ve hiç sayı atlamadı, bu nedenle numaramın maksimum değerini elde etmek için dizide kaç öğenin olduğunu bilmem gerekiyor.

VB.Net kod parçacıkları:

'''''''

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

'''''''

Dizide boşluklar olduğunda çalışmaz. Ayrıca, yalnızca tesadüfen de çalışır, çünkü öğe dizini, bu dizinde depolanan değere eşit olur. o dizi içinde depolanan en yüksek değeri değil, dizideki GetUpperBound()olası en yüksek dizini alır GetValues().
JensG

2

F # 'da, numaralandırmayı bir diziye dönüştürmek için bir yardımcı işlevle:

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   

Çalıştırmak ...

> Foo yazın = | Fizz = 3 | Patlama = 2
> val ToSeq: 'A -> seq <' B>, 'A: enum <' B> olduğunda
> val FooMax: Foo = Fizz

when 'A : enum<'B>Tanımı için derleyici tarafından gerekli değildir, ancak bu bile geçerli bir enum türüne göre, ToSeq her türlü kullanımından gereklidir.


2

Numaramın minimum ve maksimum değerlerine ihtiyacım olduğunda aşağıdakileri kullandım. Sadece numaralandırmanın en düşük değerine eşit bir min ve numaralandırmadaki enum değer olarak en yüksek değere eşit bir maks belirledim.

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!");
}

1

Her koşulda kullanılamaz, ancak genellikle maksimum değeri kendim tanımlarım:

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

Elbette bu, bir numaralandırmada özel değerler kullandığınızda işe yaramaz, ancak çoğu zaman kolay bir çözüm olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.