【发布时间】:2010-09-17 05:33:51
【问题描述】:
如何获得枚举的最大值?
【问题讨论】:
-
我认为编译器可以处理这个问题,而不是使用反射调用。对此信息使用编译时方法的答案将获得我的支持。
如何获得枚举的最大值?
【问题讨论】:
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();
编辑
对于那些不愿意阅读 cmets 的人:你也可以这样做:
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Max();
...当您的某些枚举值为负时,这将起作用。
【讨论】:
我同意马特的回答。如果您只需要最小和最大 int 值,则可以按以下方式进行。
最大值:
Enum.GetValues(typeof(Foo)).Cast<int>().Max();
最低:
Enum.GetValues(typeof(Foo)).Cast<int>().Min();
【讨论】:
根据马特汉密尔顿的回答,我想为它创建一个扩展方法。
由于ValueType 不被接受为泛型类型参数约束,我没有找到更好的方法将T 限制为Enum,但以下。
任何想法都将不胜感激。
PS。请忽略我的 VB 含蓄,我喜欢以这种方式使用 VB,这就是 VB 的优势,这就是我喜欢 VB 的原因。
Howeva,这里是:
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
}
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
【讨论】:
这有点挑剔,但任何enum 的实际最大值是Int32.MaxValue(假设它是从int 派生的enum)。将任何 Int32 值转换为任何 enum 是完全合法的,无论它是否实际声明了具有该值的成员。
法律:
enum SomeEnum
{
Fizz = 42
}
public static void SomeFunc()
{
SomeEnum e = (SomeEnum)5;
}
【讨论】:
又试了一次,得到了这个扩展方法:
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());
}
}
【讨论】:
使用 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);
}
}
【讨论】:
与 Matthew J Sullivan 一致,对于 C#:
Enum.GetValues(typeof(MyEnum)).GetUpperBound(0);
我真的不知道为什么有人会想要使用:
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last();
...逐字逐句,从语义上讲,它似乎没有多大意义? (有不同的方式总是好的,但我看不到后者的好处。)
【讨论】:
System.Enum 下有一些获取枚举类型信息的方法。
因此,在 Visual Studio 的 VB.Net 项目中,我可以键入“System.Enum”。智能感知带来了各种各样的好处。
一个特别的方法是 System.Enum.GetValues(),它返回一个枚举值的数组。一旦你得到了数组,你应该能够根据你的特定情况做任何合适的事情。
在我的例子中,我的枚举值从零开始并且没有跳过任何数字,所以要获得我的枚举的最大值,我只需要知道数组中有多少元素。
VB.Net代码sn-ps:
'''''''
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() 返回的数组中可能的最高索引,而不是存储在该数组中的最高值。
在 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 当'A : enum > val FooMax : Foo = Fizz编译器不需要when 'A : enum<'B> 进行定义,但任何使用 ToSeq 时都需要when 'A : enum<'B>,即使是有效的枚举类型也是如此。
【讨论】:
当我需要枚举的最小值和最大值时,我使用了以下内容。 我只是将一个最小值设置为枚举的最小值,并将一个最大值设置为枚举中的最大值作为枚举值本身。
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!");
}
【讨论】:
并非在所有情况下都可用,但我经常自己定义最大值:
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));
当然,当您在枚举中使用自定义值时,这将不起作用,但通常这是一个简单的解决方案。
【讨论】: