【问题标题】:Simple form of Array class and Enum.GetValues()Array 类和 Enum.GetValues() 的简单形式
【发布时间】:2012-06-04 00:54:18
【问题描述】:

我正在使用静态方法

Enum.GetValues(typeof(SomeEnum));

当您需要做的只是枚举值时,此方法非常有用,但由于某种原因,它返回了一个非常简单的 Array 类形式。 我正在尝试找到一种简单的方法将其返回值转换为更“正常”的集合类,例如常规数组或 List。

到目前为止,如果我想这样做,我必须枚举 Enum.GetValues(typeof(SomeEnum)); 的输出。并将它们一一添加到 List.

任何想法如何更干净地做到这一点?

答案:

关键是转换返回结果--

SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));

如果你需要一个列表,那么只需将它包裹在括号中并像这样 ToList :

List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();

【问题讨论】:

  • 有人花时间否决了这个问题。迷人。他可能甚至不知道这比表面上看起来要复杂得多。
  • +1 我花时间反对投反对票 :)
  • +1 表示最终让我做了一些调查并教会了我一些新东西的问题。 (如果您有兴趣,我修改了我的答案,并提供了一些有关 Array 类的附加信息,您可能会发现这些信息很有用。)

标签: c# .net


【解决方案1】:

如果您使用的是 .NET 3.5,还可以使用 Cast&lt;T&gt; 和 ToList 扩展方法。

IEnumerable<SomeEnum> enums = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();

如果你愿意,你也可以得到一个列表

List<SomeEnum> list =  Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();

【讨论】:

    【解决方案2】:

    受 Jon Skeet 的 unconstrained-melody 启发,我想出了我更喜欢的版本:

    public static class Enum<T>
        where T: struct
    {
        static Enum()
        {
            Trace.Assert(typeof(T).IsEnum);
            Values = Array.AsReadOnly((T[])Enum.GetValues(typeof(T)));
        }
    
        public static readonly ReadOnlyCollection<T> Values;
    }
    

    及用法:

    var values = Enum<BindingFlags>.Values;
    

    好在这个版本在多次调用时工作得更快,因为它不会每次都创建新数组。

    【讨论】:

    • @Konstantin:我更喜欢 UnconstrainedMelody,因为这意味着您不需要类型参数检查。我会让 type 参数检查一个普通的if (...) throw 虽然 - 如果你不处于调试模式,为什么要继续?我还要添加“where T : struct”约束——它没有 UnconstrainedMelody 提供的那么多,但它绝对比没有好。
    • 我很想接受字段/属性的想法,而不是方法调用。到目前为止,我的 Enums 类型是非泛型的,而是依靠泛型 methods 来获得类型推断的好处......但我也可以拥有一个泛型的。不过可能有点混乱。
    • 感谢 Jon,我已将 Debug 更改为 Trace 并添加了 struct 约束。我必须说我现在几乎喜欢它了。
    • 我刚想到要写一个完全一样的类。以下是一些 cmets: 如果有人使用带有错误类型参数的类(例如,Enum&lt;int&gt;),字段初始化程序不会在构造函数之前运行吗?那么在你的IsEnum类型检查之前会抛出异常吗?为什么不在构造函数的后期分配字段?无需拨打ToList();相反,您可以说Values = Array.AsReadOnly((T[])Enum.GetValues(typeof(T)));。也许您应该检查Values 是否包含重复项。如果枚举T 具有相同数值的不同“命名常量”,它将。
    • 不知道Array.AsReadOnly,谢谢。我已按照您的建议更改了代码并将readonly 添加到该字段。初始化顺序现在很清楚了。排除重复项有点超出了这个问题的范围,所以我不想这样做。
    【解决方案3】:

    found here你可以这样做:

    SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));
    

    如果您需要一个列表,只需在末尾使用 .ToList(),如下所示:

    List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
    

    或者如果你更喜欢这个:

    List<SomeEnum> list2 = new List<SomeEnum>((SomeEnum[]) Enum.GetValues(typeof(SomeEnum)));
    

    【讨论】:

    • 您的枚举名称重复了。这在编写代码时很烦人。
    【解决方案4】:

    我有一个 brand new library (UnconstrainedMelody) 可以帮助解决这个问题。它可以返回强类型数组或不可变列表中的值:

    SomeEnum[] array = Enums<SomeEnum>.GetValuesArray()
    IList<SomeEnum> list = Enums<SomeEnum>.GetValues();
    

    它是通用的,并且对类型参数有一个约束,以确保它是真正的枚举。这在普通的 C# 中是不可能的,但是该库做了一些工作以使其工作。我更喜欢第二种形式,因为我们缓存了列表——它是不可变的,这意味着我们可以一次又一次地返回相同的引用。

    还有各种其他实用方法可以更轻松地使用标志枚举等。

    享受吧。

    【讨论】:

    • 嗨乔恩,我看了你的链接。你找到了一种方法来陪审团装配编译器真是太酷了:)
    • 嗨,乔恩,我想下载源代码,所以我去我的 Tortoise SVN 右键单击​​并选择导入。然后输入:unconstrained-melody.googlecode.com/svn/trunk unconstrained-melody-read-only,这要求我登录...所以我尝试了以下操作:unconstrained-melody.googlecode.com/svn/trunk,同样的事情...我怎样才能获得源代码?
    • 嗯...我不确定为什么匿名访问不起作用。您可以通过选择“浏览”来查看单个文件 - 但我会尝试在一分钟内获取源下载...
    • 好的,源 zip 文件现已创建:code.google.com/p/unconstrained-melody/downloads/list
    • Svn 匿名访问现在似乎又恢复了...我正要通知相应的团队,但它对我有用 :)
    【解决方案5】:

    这应该可行:

    List<MyEnum> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToList();
    

    ToList() 在您在问题中发布的解决方案中不起作用的原因是您在铸造部分周围缺少一组括号。希望这会有所帮助!

    【讨论】:

    • 这个答案的原因: List values = new List(Enum.GetValues(typeof(SomeEnum)));没有编译是因为缺少 (SomeEnum[]) 演员...
    • 啊,我正在查看您在原始问题末尾包含的代码(包括演员表)。对不起! :)
    • 别担心,我只是澄清一下:)
    【解决方案6】:

    修订版(2009 年 9 月 12 日 ~2:20 PM EST)

    所以,我昨晚提出这个建议是基于Enum.GetValues 返回一个Array,我认为Array 实现了IEnumerable&lt;T&gt;

    我相信你可以构建一个 List&lt;T&gt; 传递任何 IEnumerable&lt;T&gt; 作为构造函数的参数。 所以你应该可以这样做:

    List<SomeEnum> values = new List<SomeEnum>(Enum.GetValues(typeof(SomeEnum)));
    

    但是,GordonG 很快回复了我的回答,表明它无法编译。 (通常我会测试我的答案,但当时我在一台没有任何开发工具的计算机上,并且对自己感到非常[不合理地]确定。)

    经过一些否决和深思熟虑后,我决定弄清楚这件事(经过一夜好眠)。 事实证明,根据 Microsoft 关于 Arrayhere 的文档,Array 确实实现了 IEnumerable&lt;T&gt;,但仅在运行时(所以,不是在编译时——因此编译失败)。事后看来,这是有道理的:Enum.GetValues 不是泛型方法,因此它无法事先知道要返回哪种泛型集合。 (至少我是这么理解的。)

    无论如何,这一切意味着您可以合法地将Array 转换为IEnumerable&lt;T&gt;,前提是您的类型正确。因此,我终于可以提出我的最终答案了,这与我最初的答案实际上是一样的,但加入了一个简单的演员表以使一切合法:

    // splitting into two lines just for readability's sake
    List<SomeEnum> values;
    values = new List<SomeEnum>((IEnumerable<T>) Enum.GetValues(typeof(SomeEnum)));
    

    当然,回想起来,GordonG 并没有下定决心要获得List&lt;T&gt;,这意味着他自己的选择SomeEnum[] 的答案真的一样好。

    【讨论】:

    • 您还可以创建一个 List 并为其 AddRange 方法提供一个数组。
    • 老兄,你因为一些甚至无法编译的东西而获得投票! ;)
    • AddRange 也无法编译。
    • 丹,呵呵,那也行不通。现在你明白我为什么问这个看似简单的问题了。 Enum.GetValues() 返回一些奇怪的古老形式的 Array。
    • @GordonG:但是在您的回答中,您正在转换为 SomeEnum 数组,除非我弄错了,否则它应该实现 IEnumerable?你试过那个,它也没有编译吗?也许为时已晚...
    【解决方案7】:

    .NET 框架 2.0 的更新解决方案(来自“Konstantin Spirin”):

    public static class Enum<T> where T : struct
    {
        static Enum()
        {
            Trace.Assert(typeof(T).IsEnum);
        }
    
        public static ReadOnlyCollection<T> Values = new ReadOnlyCollection<T>(((T[])Enum.GetValues(typeof(T))));
    }
    

    【讨论】:

      【解决方案8】:

      这个怎么样:

          List<SomeEnum> list = new List<SomeEnum>();
          foreach (SomeEnum value in Enum.GetValues (typeof (SomeEnum)))
          {
              if (condition)
                  list.Add(value);
          }
      

      【讨论】:

      • 这就是我已经拥有的 :) 我想我找到了一个更清洁的解决方案。让我发一下。
      • 好吧,下次您应该在问题中包含您已经拥有的内容。你最初说过你想要一个解决方案来逐个添加项目......
      • 伊戈尔,请重新阅读我的问题。我要求一种将返回值 eof Enum.GetValues() 转换为 List 数组的方法
      • 好的,我很抱歉......今天太早了:(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多