【问题标题】:How to generate a random number in the constructor of a class in C#如何在 C# 类的构造函数中生成随机数
【发布时间】:2011-07-22 06:48:47
【问题描述】:

我知道在 C# 中调用类的构造函数中的方法不是一个好习惯,但我遇到了一些奇怪的问题。我的问题是,当我创建我的类的对象时,我需要在我的对象中分配一个带有随机数的字段。

例如

class RandomNumberHandler
    {
        private int randomNumber;
        public RandomNumberHandler()
        {
            this.randomNumber = GenerateRandomNumber();
        }

        private int GenerateRandomNumber()
        {
            return (new Random()).Next(3000) + 1000;
        }
    }

就我而言,我需要一个四位数字。我想在创建对象的类中生成随机数并将其作为参数传递给构造函数,但在另一个类中生成随机数似乎也不是一个好主意,因为我正在努力实现强凝聚力为我的课。我正在为我大学的“高质量代码”课程做这件事,我正在寻找最好的方法。欢迎任何想法如何做到这一点:)

【问题讨论】:

  • 在构造函数中调用正在构造的对象虚拟(包括抽象)方法不是一个好习惯。调用方法很好,确实很正常。

标签: c# methods random constructor


【解决方案1】:

首先:在构造函数中调用非虚拟方法没有错。你在哪里读到的? (注意:调用 virtual 方法可能是个问题;这不是一个自动的禁忌,但你需要非常仔细地观察你在做什么。

顺便说一句,每次调用GenerateRandomNumber 时生成一个新的Random 实例似乎很浪费。您可以将Random 实例提取到一个字段来解决这个问题:

class RandomNumberHandler
{
    private readonly Random random = new Random();
    private int randomNumber;

    public RandomNumberHandler()
    {
        this.randomNumber = GenerateRandomNumber();
    }

    private int GenerateRandomNumber()
    {
        return this.random.Next(3000) + 1000;
    }
}

但这又引发了另一个问题:如果GenerateRandomNumber 在每个实例的生命周期中(在构造函数中)只被调用一次,那么为每个对象创建一个新的Random 是没有意义的。所以下一个合乎逻辑的步骤是使random 成为static。这意味着GenerateRandomNumber 也可以变成static(事实上,它必须如此):

class RandomNumberHandler
{
    private static readonly Random Random = new Random();
    private int randomNumber;

    public RandomNumberHandler()
    {
        this.randomNumber = GenerateRandomNumber();
    }

    private static int GenerateRandomNumber()
    {
        return Random.Next(3000) + 1000;
    }
}

【讨论】:

  • 谁知道呢……这些老师总是不得不强加他们对如何做事的看法。我总是顺其自然。
  • 在构造函数中调用 virtual 方法有一些注意事项。
  • 可能他对虚方法感到困惑。
  • @Kirk,@Eric:当然。但关键是让 OP 用他自己的话来表达这一点,这样他就可以提高自己的理解力。
  • @Jon,也许吧。但是这个声明(不少于粗体),“在构造函数中调用方法没有错”让我觉得是错误的,或者充其量是不完整的。
【解决方案2】:

这段代码可以正常工作 - 除了如果你快速连续调用它,你可能会得到“相同”的随机数。

当然,您可以通过使用静态随机数轻松解决这个问题(如果您使用多个线程,请使用锁以确保线程安全),例如:

class RandomNumberHandler
{
    private static Random random = new Random();
    private static object syncObj = new object();

    private int randomNumber;
    public RandomNumberHandler()
    {
        this.randomNumber = GenerateRandomNumber();
    }

    private static int GenerateRandomNumber()
    {
        lock(syncObj)
            return random.Next(3000) + 1000;
    }
}

【讨论】:

  • +1 虽然它与其他两个答案相似,但它是唯一一个线程安全的。
  • @Jon:当我发布它时,它是唯一使用静态的版本;)
【解决方案3】:

Random number generator only generating one random number

简短回答:您应该在所有 Next() 调用中使用相同的 Random 实例。

【讨论】:

    【解决方案4】:

    仅将 Random 类包装在另一个名为 RandomHandler 的类中,我看不到任何凝聚力。就个人而言,我认为这很尴尬。如果您需要一个全新的完全随机数,则只需调用 Random().Next(3000) 或您所说的构造函数内部的任何内容。

    【讨论】:

      【解决方案5】:

      如果将Random 实例提升为静态字段并将GenerateRandomNumber 设为静态,则可以在randomNumber 字段的声明中调用它:

      class RandomNumberHandler {
        private static Random random = new Random();
        private int randomNumber = GenerateRandomNumber();
      
        private static int GenerateRandomNumber() {
          return random.Next(3000) + 1000;
        }
      }
      

      或者更简单(可读性较差):

      class RandomNumberHandler {
        private static Random random = new Random();
        private int randomNumber = random.Next(3000) + 1000;
      }
      

      虽然看起来你不是在调用构造函数中的方法,但如果你查看生成的 CIL,你会发现你是。

      另外,如果您关心线程安全,请查看article

      【讨论】:

        猜你喜欢
        • 2016-07-17
        • 2018-01-19
        • 1970-01-01
        • 2011-12-23
        • 2019-04-07
        • 1970-01-01
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        相关资源
        最近更新 更多