【问题标题】:Finding the Highest Value in an Enumeration查找枚举中的最大值
【发布时间】:2010-12-17 08:39:49
【问题描述】:

我正在编写一种方法来确定 .NET 枚举中的最大值,因此我可以为每个枚举值创建一个 BitArray:

pressedKeys = new BitArray(highestValueInEnum<Keys>());

我在两个不同的枚举上都需要这个,所以我把它变成了一个泛型方法:

/// <summary>Returns the highest value encountered in an enumeration</summary>
/// <typeparam name="EnumType">
///   Enumeration of which the highest value will be returned
/// </typeparam>
/// <returns>The highest value in the enumeration</returns>
private static int highestValueInEnum<EnumType>() {
  int[] values = (int[])Enum.GetValues(typeof(EnumType));
  int highestValue = values[0];
  for(int index = 0; index < values.Length; ++index) {
    if(values[index] > highestValue) {
      highestValue = values[index];
    }
  }

  return highestValue;
}

如您所见,我将 Enum.GetValues() 的返回值转换为 int[],而不是 EnumType[]。这是因为我不能稍后将 EnumType(这是一个泛型类型参数)转换为 int。

代码有效。但它有效吗? 我总是可以将 Enum.GetValues() 的返回值转换为 int[] 吗?

【问题讨论】:

标签: c# arrays enums


【解决方案1】:

不,您不能安全地投射到 int[]。枚举类型并不总是使用 int 作为基础值。如果您将自己限制为 确实 具有int 基础类型的枚举类型,那应该没问题。

这感觉就像您(或我)可以根据需要扩展 Unconstrained Melody 以支持 - 以一种在编译时真正将类型限制为枚举类型的方式,并且适用于任何 enum 类型,即使是具有底层基础的那些,例如 longulong

如果没有 Unconstrained Melody,您仍然可以使用所有枚举类型有效地适当地实现 IComparable 的事实以一般方式执行此操作。如果您使用的是 .NET 3.5,它是单行的:

private static TEnum GetHighestValue<TEnum>() {
  return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max();
}

【讨论】:

  • 乔恩,如果我不能将任何其他类型分配给枚举值,除了 int32 之外的其他整数类型,为什么 Microsoft 参考资料会说“枚举元素的默认基础类型是 int”。我只是尝试将 3L 分配给枚举值并得到编译错误。
  • 感谢您报告循环中的扭曲分配。我自己已经发现了它,并且忍者在你写帖子的时候已经有了一个更正的版本;-)
  • @André Pena:default 底层类型是枚举,但您可以将枚举声明为“enum Foo : long”(等等)。有关详细信息,请参阅 C# 语言规范。
  • @Jo Skeet:现在我完全理解了。只要我将枚举声明为长枚举,我就可以为枚举项分配 3L 值。 :) 谢谢。
【解决方案2】:

根据 Jon Skeet 的建议(也谢谢你,笨蛋),这是更新后的代码,现在使用 IComparable,因为我仍然以 .NET 2.0 为目标。

/// <summary>Returns the highest value encountered in an enumeration</summary>
/// <typeparam name="EnumType">
///   Enumeration of which the highest value will be returned
/// </typeparam>
/// <returns>The highest value in the enumeration</returns>
private static EnumType highestValueInEnum<EnumType>() where EnumType : IComparable {
  EnumType[] values = (EnumType[])Enum.GetValues(typeof(EnumType));
  EnumType highestValue = values[0];
  for(int index = 0; index < values.Length; ++index) {
    if(values[index].CompareTo(highestValue) > 0) {
      highestValue = values[index];
    }
  }

  return highestValue;
}

对于获取代码的任何人,您可能需要添加一个额外的检查,这样它就不会在空枚举上崩溃。

【讨论】:

  • 肯定Array.Sort&lt;EnumType&gt;(values); 会比你的循环更好?
  • 它会更短,但是为什么要对我完成后要扔掉的数组进行排序呢?也许我在这里进行了微优化,但 Array.Sort() 对我来说似乎并不直观。
【解决方案3】:

简单!使用 LINQ,您的循环可以替换为两行代码,或者如果您想将所有代码组合在一起,则只需一行代码。

public partial class Form1 : Form
{
    private void Form1_Load(object sender, EventArgs e)
    {
        MyEnum z = MyEnum.Second;
        z++;
        z++;

        //see if a specific value is defined in the enum:
        bool isInTheEnum = !Enum.IsDefined(typeof(MyEnum), z);

        //get the max value from the enum:
        List<int> allValues = new List<int>(Enum.GetValues(typeof(MyEnum)).Cast<int>());
        int maxValue = allValues.Max();
    }


}

public enum MyEnum 
{
    Zero = 0,
    First = 1,
    Second = 2,
    Third = 3
}

【讨论】:

  • 为什么还要创建 List&lt;int&gt; 呢?无需缓冲所有值...
  • 你是完全正确的,我可以把它写成 var max = (from int x in Enum.GetValues(typeof(MyEnum)).AsQueryable() select x).Max();但这不是一段看起来很友好的代码,我想把它分解一下,使代码易于阅读和信息丰富。而且我不认为“缓冲值”比遍历它们以找到最高值更不理想。
【解决方案4】:

使用一些现代 C# 特性,我们可以更优雅地做到这一点:

static int MaxEnumValue<T>()
    where T : struct, Enum
{
    return (int)(ValueType)Enum.GetValues<T>().Max();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 2010-09-17
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多