Guf*_*ffa 2348
在Random
类用于创建随机数.(当然是伪随机的.).
例:
Random rnd = new Random();
int month = rnd.Next(1, 13); // creates a number between 1 and 12
int dice = rnd.Next(1, 7); // creates a number between 1 and 6
int card = rnd.Next(52); // creates a number between 0 and 51
Run Code Online (Sandbox Code Playgroud)
如果要创建多个随机数,则应保留Random
实例并重复使用它.如果您创建新实例的时间太近,它们将生成与随机生成器从系统时钟播种相同的随机数序列.
Shi*_*ala 248
问题看起来很简单,但答案有点复杂.如果你看到几乎每个人都建议使用Random类,有些人建议使用RNG加密类.但是什么时候选择什么.
为此,我们首先需要理解"随机性"一词及其背后的哲学.
我鼓励你观看这段视频,该视频深入探讨了随机使用C#https://www.youtube.com/watch?v= tCYxc-2-3fY
首先让我们了解RANDOMNESS的哲学.当我们告诉一个人在RED,GREEN和YELLOW之间做出选择时会发生什么.是什么让人选择RED或YELLOW或GREEN?
最初的想法是进入决定他选择的人的心灵,它可以是喜欢的颜色,幸运的颜色等.换句话说,我们将RANDOM中的一些初始触发器称为SEED.此SEED是起始点,触发器促使他选择RANDOM值.
现在,如果SEED易于猜测,那么这些随机数被称为PSEUDO,当种子难以猜测时,这些随机数被称为 SECURED随机数.
例如,一个人根据天气和声音组合选择颜色,那么很难猜测初始种子.
现在让我作一个重要的声明: -
*"Random"类仅生成PSEUDO随机数并生成SECURE随机数,我们需要使用"RNGCryptoServiceProvider"类.
随机类从您的CPU时钟获取种子值,这是非常可预测的.所以换句话说,CAND的RANDOM类生成伪随机数,下面是相同的代码.
var random = new Random();
int randomnumber = random.Next()
Run Code Online (Sandbox Code Playgroud)
而RNGCryptoServiceProvider类使用OS熵来生成种子.OS熵是一个随机值,它是使用声音,鼠标点击和键盘时序,热温等生成的.下面是相同的代码.
using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
{
byte[] rno = new byte[5];
rg.GetBytes(rno);
int randomvalue = BitConverter.ToInt32(rno, 0);
}
Run Code Online (Sandbox Code Playgroud)
要了解操作系统熵,请参阅此视频,请访问14:30 https://www.youtube.com/watch?v=tCYxc-2-3fY,其中解释了操作系统熵的逻辑.因此,使用简单的单词RNG Crypto会生成SECURE随机数.
Pan*_*hra 223
每次执行新的Random()时都会初始化.这意味着在紧密循环中,您可以多次获得相同的值.您应该保留一个Random实例并继续在同一个实例上使用Next.
//Function to get random number
private static readonly Random getrandom = new Random();
public static int GetRandomNumber(int min, int max)
{
lock(getrandom) // synchronize
{
return getrandom.Next(min, max);
}
}
Run Code Online (Sandbox Code Playgroud)
Fyo*_*kin 86
注意new Random()
在当前时间戳上播种.
如果您只想生成一个数字,可以使用:
new Random().Next( int.MinValue, int.MaxValue )
有关更多信息,请查看Random类,但请注意:
但是,由于时钟具有有限的分辨率,使用无参数构造函数以紧密连续的方式创建不同的随机对象会创建随机数生成器,从而生成相同的随机数序列
所以不要使用此代码生成一系列随机数.
Jor*_*ren 48
Random r = new Random();
int n = r.Next();
Run Code Online (Sandbox Code Playgroud)
小智 27
我想添加一个加密安全版本:
RNGCryptoServiceProvider类(MSDN或dotnetperls)
它实现了IDisposable.
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] randomNumber = new byte[4];//4 for int32
rng.GetBytes(randomNumber);
int value = BitConverter.ToInt32(randomNumber, 0);
}
Run Code Online (Sandbox Code Playgroud)
Mis*_*sky 19
正如其他答案中所述,一个好的安全方法是使用安全密码生成器。这里的所有示例都显示了与我建议的解决方案相比,其用法RNGCryptoServiceProvider
是编写很长的代码。
使用写在加密 API\xe2\x80\x99s 之上的RandomNumberGenerator 。它RNGCryptoServiceProvider
与随机性一样安全。
// Gives a random number for the integer range.\n// You can simply update the parameters as your needs.\nRandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);\n
Run Code Online (Sandbox Code Playgroud)\n
mbc*_*ump 16
您可以在他为伪随机数构建的MiscUtil类库中使用Jon Skeet的StaticRandom方法.
using MiscUtil;
...
for (int i = 0; i < 100;
Console.WriteLine(StaticRandom.Next());
Run Code Online (Sandbox Code Playgroud)
Moh*_*lim 14
最好用当前的毫秒种子Random对象,以确保真正的随机数,你几乎不会发现多次使用它的重复
Random rand = new Random(DateTime.Now.Millisecond);
Run Code Online (Sandbox Code Playgroud)
更新
我知道new Random()
使用当前的滴答作为种子,但播种当前毫秒仍然足够好,因为它是良好的随机启动
最后一点是你不必new Random()
每次需要一个随机数时初始化,启动一个Random对象然后在循环内或其他任何时候使用它多次
Pro*_*imo 13
我已经尝试了所有这些解决方案,不包括COBOL答案...大声笑
这些解决方案都不够好.我需要在快速的int循环中使用random,即使在很宽的范围内,我也会获得大量的重复值.在解决了一段随机结果后,我决定一劳永逸地解决这个问题.
这都是关于种子的.
我通过解析Guid中的非数字来创建一个随机整数,然后我用它来实例化我的Random类.
public int GenerateRandom(int min, int max)
{
var seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
return new Random(seed).Next(min, max);
}
Run Code Online (Sandbox Code Playgroud)
更新:如果您实例化一次Random类,则无需播种.因此,最好创建一个静态类并从中调用一个方法.
public static class IntUtil
{
private static Random random;
private static void Init()
{
if (random == null) random = new Random();
}
public static int Random(int min, int max)
{
Init();
return random.Next(min, max);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用静态类.
for(var i = 0; i < 1000; i++)
{
int randomNumber = IntUtil.Random(1,100);
Console.WriteLine(randomNumber);
}
Run Code Online (Sandbox Code Playgroud)
我承认我更喜欢这种方法.
Jeb*_*Hut 10
从这里修改答案。
如果您有权访问兼容Intel Secure Key的CPU,则可以使用以下库生成实际的随机数和字符串:https : //github.com/JebteK/RdRand和https://www.rdrand.com/
只需从此处下载最新版本,包括Jebtek.RdRand并为其添加using语句即可。然后,您需要做的就是:
// Check to see if this is a compatible CPU
bool isAvailable = RdRandom.GeneratorAvailable();
// Generate 10 random characters
string key = RdRandom.GenerateKey(10);
// Generate 64 random characters, useful for API keys
string apiKey = RdRandom.GenerateAPIKey();
// Generate an array of 10 random bytes
byte[] b = RdRandom.GenerateBytes(10);
// Generate a random unsigned int
uint i = RdRandom.GenerateUnsignedInt();
Run Code Online (Sandbox Code Playgroud)
如果没有兼容的CPU来执行代码,只需使用rdrand.com上的RESTful服务即可。使用项目中包含的RdRandom包装器库,您只需要这样做(注册时可获得1000个免费呼叫):
string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
Run Code Online (Sandbox Code Playgroud)
小智 9
内置Random
类(System.Random)生成的数字生成伪随机数.
如果你想要真正的随机数,我们可以得到的最接近的是"安全伪随机生成器",它可以通过使用C#中的加密类生成RNGCryptoServiceProvider
.
即便如此,如果您仍然需要真正的随机数,您将需要使用外部源,例如考虑放射性衰变的设备作为随机数生成器的种子.因为,根据定义,纯粹算法手段产生的任何数字都不能真正随机.
在 .NET 6 中,您可以使用Random.Shared:
int random = Random.Shared.Next();
Run Code Online (Sandbox Code Playgroud)
在 .NET 8 预览版中,此类添加了许多新的缺失方法,例如随机排列数组等。
我使用下面的代码来获得一个随机数:
var random = new Random((int)DateTime.Now.Ticks);
var randomValue = random.Next(startValue, endValue + 1);
Run Code Online (Sandbox Code Playgroud)
虽然这没关系:
Random random = new Random();
int randomNumber = random.Next()
Run Code Online (Sandbox Code Playgroud)
大多数时候您都希望控制限制(最小和最大数量)。所以你需要指定随机数的开始和结束位置。
该Next()
方法接受两个参数,min 和 max。
因此,如果我希望我的随机数介于 5 和 15 之间,我会这样做
int randomNumber = random.Next(5, 16)
Run Code Online (Sandbox Code Playgroud)
作为注释以备将来参考。
如果您使用 .NET Core,则多个 Random 实例不像以前那么危险。我知道这个问题是从 2010 年开始的,但由于这个问题很老但有一些吸引力,我认为记录更改是一件好事。
您可以参考我不久前提出的这个问题:
基本上,他们已将默认种子从 更改Environment.TickCount
为Guid.NewGuid().GetHashCode()
,因此如果您创建 Random 的 2 个实例,它将不会显示相同的数字。
您可以在此处查看 .NET Framework/.NET Core (2.0.0+) 的文件差异:https : //github.com/dotnet/coreclr/pull/2192/commits/9f6a0b675e5ac0065a268554de49162c539ff66d
它不如 RNGCryptoServiceProvider 安全,但至少它不会给你奇怪的结果。
小智 5
这是我使用的课程。像RandomNumber.GenerateRandom(1, 666)
internal static class RandomNumber
{
private static Random r = new Random();
private static object l = new object();
private static Random globalRandom = new Random();
[ThreadStatic]
private static Random localRandom;
public static int GenerateNewRandom(int min, int max)
{
return new Random().Next(min, max);
}
public static int GenerateLockedRandom(int min, int max)
{
int result;
lock (RandomNumber.l)
{
result = RandomNumber.r.Next(min, max);
}
return result;
}
public static int GenerateRandom(int min, int max)
{
Random random = RandomNumber.localRandom;
if (random == null)
{
int seed;
lock (RandomNumber.globalRandom)
{
seed = RandomNumber.globalRandom.Next();
}
random = (RandomNumber.localRandom = new Random(seed));
}
return random.Next(min, max);
}
}
Run Code Online (Sandbox Code Playgroud)
我想演示每次使用新的随机生成器时会发生什么。假设您有两个方法或两个类,每个方法或两个类都需要一个随机数。你天真地把它们编码为:
public class A
{
public A()
{
var rnd=new Random();
ID=rnd.Next();
}
public int ID { get; private set; }
}
public class B
{
public B()
{
var rnd=new Random();
ID=rnd.Next();
}
public int ID { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
你认为你会得到两个不同的ID吗?没有
class Program
{
static void Main(string[] args)
{
A a=new A();
B b=new B();
int ida=a.ID, idb=b.ID;
// ida = 1452879101
// idb = 1452879101
}
}
Run Code Online (Sandbox Code Playgroud)
解决方案是始终使用单个静态随机生成器。像这样:
public static class Utils
{
public static readonly Random random=new Random();
}
public class A
{
public A()
{
ID=Utils.random.Next();
}
public int ID { get; private set; }
}
public class B
{
public B()
{
ID=Utils.random.Next();
}
public int ID { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)