【问题标题】:Choose a random static variable from a static class从静态类中选择一个随机静态变量
【发布时间】:2013-06-05 08:01:02
【问题描述】:

我有一个静态类中的静态变量列表。

namespace Test
{
  public static class Numbers
  {
    public static readonly int One = 1;
    public static readonly int Five = 5;
    public static readonly int Ten = 10;
    public static readonly int Eleven = 11;
    public static readonly int Fifteen= 15;
  }
}

我想在类中随机选择一个变量。我怎样才能做到这一点?

int randomVariable = SomeFunction(Numbers);

【问题讨论】:

  • @makc:Numbers 类来自第三方 dll
  • @RameshDurai 这并不妨碍您将其所有静态变量复制到您自己的数组中。
  • 对于您的示例,这是微不足道的,因此我想还有更多。您是否提前知道课程类型,例如您的示例?
  • @MatthewWatson:是的。我提前知道班级类型..

标签: c# .net static


【解决方案1】:

使用反射:

FieldInfo[] fields= typeof(Numbers).GetFields(
   BindingFlags.Public | BindingFlags.Static);

var rnd = new Random();
int randomVariable = (int) fields[rnd.Next(fields.Length)].GetValue(null);

无需反思的更好解决方案:

创建一个整数数组Numbers作为静态属性并将其初始化为Numbers类中的值:

Numbers = fields.Select(f => (int)f.GetValue()).ToArray(); //int[]

那么当得到一个随机值时:

int randomVariable = Numbers[rnd.Next(Numbers.Length)];

【讨论】:

  • +1,但不要忘记您真的希望您的 Random 位于成员变量或静态变量中,而不是像这样的局部变量。
【解决方案2】:
  var fields = typeof(Numbers).GetFields(BindingFlags.Static | BindingFlags.Public);
  var value = fields
         .OrderBy(x => Guid.NewGuid()) // order by random
         .First() // take first field
         .GetValue(null); // get it's value

但总的来说,静态字段的使用非常奇怪,如果一切正常,我会审查设计。

【讨论】:

  • Guid.NewGuid()好像有点重,为什么不用Random呢?
  • 我认为使用反射比使用 Guid 更重,所以使用 Guid 更短:)
  • Guid 不是随机的,不应用于此目的。 stackoverflow.com/questions/467271/…
【解决方案3】:

你可以创建一个int数组,在上下数组索引之间生成一个随机数,并用它访问数组索引。

否则,对于您的工作方法,必须使用反射,这会降低性能并且不是很优雅。例如,获取类中的所有 PropertyInfo,用它们创建和排列,获取和随机索引并调用PropertyInfo 值。

【讨论】:

    【解决方案4】:

    您可以在课堂上使用reflection 来做到这一点。请注意,如果您不想枚举所有 const int,则需要在它们上添加要枚举的标记。这将使用自定义 Attributes 来完成。

    namespace ConsoleApplication4
    {
      using System;
      using System.Collections.Generic;
      using System.Linq;
    
      public class Holder
      {
        public const int Number1 = 7;
    
        public const int Number2 = 17;
    
        public const int Number3 = 42;
    
        public static IEnumerable<int> AllNumbers()
        {
          return
            typeof(Holder).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
                          .Where(p => p.FieldType == typeof(int))
                          .Select(p => (int)p.GetValue(null));
        }
    
        public static int RandomNumber(Random r)
        {
          var possibleNumbers = AllNumbers().ToList();
    
          var draw = r.Next(possibleNumbers.Count);
    
          return possibleNumbers[draw];
        }
      }
    
      public class Program
      {
        public static void Main()
        {
          var r = new Random();
    
          for (int i = 0; i < 10; i++)
          {
            Console.WriteLine(Holder.RandomNumber(r));
          }
    
          Console.WriteLine("Done");
          Console.ReadLine();
        }
      }
    }
    

    【讨论】:

      【解决方案5】:

      既然你知道类型,你就不需要反射 - 所以像这样简单的事情应该没问题:

      public sealed class NumbersRandomizer
      {
          readonly Random rng = new Random();
      
          public int RandomValue()
          {
              switch (rng.Next(5))
              {
                  case 0: return Numbers.One;
                  case 1: return Numbers.Five;
                  case 2: return Numbers.Ten;
                  case 3: return Numbers.Eleven;
                  case 4: return Numbers.Fifteen;
              }
          }
      }
      

      你会这样使用:

      var randomizer = new NumbersRandomizer();
      int value = randomizer.RandomValue();
      

      【讨论】:

      • 这个解决方案看起来不错。但问题是,Numbers 类中有近 100 个变量。编写 switch case 会很困难。
      • @RameshDurai 你的意思不是“困难”——你的意思是“乏味和耗时”。 ;)
      • 那么您确定,由于您使用的是第 3 方类型,因此第 3 方将来不会添加您的公共只读属性i> 想要包含在随机数中?因为如果你使用反射,那可能会发生。
      • @RameshDurai 抱歉,我只是没有注意到先发布的内容。艾哈迈德是第一个,所以这是可以选择的。 :)
      【解决方案6】:

      如果您使用Enum,这可以更容易实现。

      public enum Numbers {
          One = 1,
          Five = 5,
          Ten = 10,
          Eleven = 11
          Fifteen = 15
      }
      

      然后随机选择枚举。

      var numbers = Enum.GetValues(typeof(Numbers));
      
      Number randomNumber = (Number)numbers.GetValue(new Random().Next(numbers.Length));
      

      【讨论】:

        猜你喜欢
        • 2015-10-04
        • 1970-01-01
        • 2012-09-06
        • 1970-01-01
        • 1970-01-01
        • 2011-09-01
        • 2018-07-04
        • 2018-09-15
        相关资源
        最近更新 更多