C# System.Random 扩展





5.00/5 (17投票s)
一个有用的简单扩展方法库,
引言
当开始处理一个需要大量数据的新项目时,数据本身可能尚未存在。 然而,在开发阶段,为了测试目的,仍然需要一些数据。 当然,手动添加一些虚拟数据总是一个选择,但真正的开发者倾向于将这项工作交给计算机。 因此,就提出了数据生成的问题。
如果谈论一个 C# 项目,数据生成意味着使用 System.Random
类,这很合适,但不幸的是缺少一些有用的特性。 我尝试改进一下情况,并编写了一些可能派上用场的扩展方法。
使用代码
除了库本身,源代码还包含一个带有注释的工作示例。
以下是一些[编辑过的]代码片段
日期生成
有一个 NextDate
方法,它的使用方式与 Random
类中的标准 Next
方法相同,但它返回 DateTime 对象而不是整数
Random _random = new Random();
// Date of birth is a date between 1/1/1800 and a day that was 25 years ago
DateTime birthFrom = new DateTime(1800, 1, 1);
DateTime birthTo = DateTime.Now.AddYears(-25);
DateTime birthDate = _random.NextDate(birthFrom, birthTo);
可以省略范围限制。 请注意,DateTime
变量的 Time
部分在这里被清零;但也有一个 NextDateTime
方法。 还有一个 NextLong
方法,它们都基于此。
从数组中选择随机项
是的,使用 Random
类的 Next
方法从列表/数组中选择一个随机项并不困难,但以下代码稍微简洁一些
Random _random = new Random();
string[] _lastNames = { "Johnson", "King", "Verne", "Hawk", "Sterling", "Stout", "Webster", "Knight", "Aston", "Anderson" };
string lastName = _random.NextItem(_lastNames);
使用概率检查
再次说明,可以使用标准方法实现,但这段代码更短且相当清晰。
Random _random = new Random();
string[] _firstNames = { "John", "Rex", "Andrew", "Jonathan", "Stephen", "Frederick", "Louis", "Matthew" };
string middleName = null;
// ...
// 1/3 persons to have a middle name
if (_random.HitBullsEye(3))
{
// in 3 of 10 cases middle name is just a letter (like Jerome K. Jerome)
middleName = _random.IsTrueWithProbability(0.3)
? $"{(char)('A' + _random.Next(0, 26))}."
: _random.NextItem(_firstNames);
}
请注意,HitBullsEye
方法实际上是将飞镖投向射击目标(在本例中,由 3 个圆圈组成),并且仅在击中目标的靶心时才返回 true。
但是,如果您愿意,您可以投掷一个虚拟骰子,如下所示
// 1/2 males, 1/2 females
Person.PersonSex sex = _random.ThrowDiceToHit(2, 2) ? Person.PersonSex.Male : Person.PersonSex.Female;
(在 ThrowDiceToHit
方法中,第一个参数是骰子的面数,第二个参数是最低“获胜”值。 因此,ThrowDiceToHit(6, 3) 仅当骰子的上方面显示 3 到 6 的数字时才返回 true,即在 2/3 的情况下。)
此外,您可以将概率检查与选择列表项结合起来
// Females could have a maiden name...
if (sex == Person.PersonSex.Female)
{
// ... in 7 of 10 cases
maidenName = _random.NextItemOrDefault(_lastNames, 0.7);
}
关注点
由于这些方法基于 System.Random
类的标准 Next
和 NextDouble
方法,因此我不建议在需要安全性或强可靠性的任务中使用它们。(我甚至不确定 NextLong
方法是否会覆盖 long 大小范围的所有 long 值。) 但它们非常适合测试数据生成器。 另外,我认为掷骰子的部分在游戏中也可能很有用。
历史
这是文章的第一个版本。 如果库发生变化,我会尝试更新它。 但您可以始终在 GitHub 上获取最新版本的代码。