一、随机数核心原理
1. 伪随机数概念
计算机中没有真正的随机数。
代码生成的随机数都是伪随机(假随机):
通过固定算法 + 初始种子 → 计算出一串固定数字序列,我们只是依次从队列中取出数字
2. 种子规则(核心)
C#会自动使用当前系统的时间作为种子
-
种子相同 → 随机数序列完全相同
-
种子不同 → 随机数序列不同
-
不手动指定种子:默认以当前系统时间作为种子
3. 使用场景
账号注册、唯一ID、随机点名、抽奖、验证码、秘钥生成等
二、Random 普通随机数(最常用)
1. 固定种子(随机数可复现)
手动指定种子,种子一致,随机数序列完全一致。
// 指定种子为10
Random rnd = new Random(10);
Console.WriteLine(rnd.Next());
// 两个对象种子相同,生成的随机数完全一致
Random rnd2 = new Random(100);
Random rnd3 = new Random(100);
Console.WriteLine(rnd2.Next() + ":" + rnd3.Next());
Console.WriteLine(rnd2.Next() + ":" + rnd3.Next());
2. 默认种子(时间种子,真正随机)
不写种子,默认使用系统时间作为种子,时间一直在变,所以随机数不同。
Random rnd4 = new Random();
// Next(最小值,最大值) 包含最小值,不包含最大值
Console.WriteLine(rnd4.Next(10, 21)); // 10~20
// Next(最大值) 默认从0开始,不包含最大值
Console.WriteLine(rnd4.Next(21)); // 0~20
3. 高频大坑:循环内new Random()
绝对不要在for循环里面new Random对象!
原因:循环执行速度极快,毫秒时间一致 → 种子一致 → 每次随机数一模一样。
// 正确写法:对象只创建一次
Random rnd5 = new Random();
for (int i = 0; i < 4; i++)
{
Console.WriteLine(rnd5.Next());
}
// 错误写法!!!
//for (int i = 0; i < 4; i++)
//{
// Random rndErr = new Random();
// Console.WriteLine(rndErr.Next());
//}
三、实战:随机生成字符 / 验证码
方式1:通过字符串下标随机取值
cs
// 小写字母库
string s = "qwertyuiopasdfghjklzxcvbnm";
Random rnd6 = new Random();
// 随机取出一个字符
int num1 = rnd6.Next(s.Length);
Console.WriteLine(s[num1]);
// 生成4位随机字符验证码
Random rnd7 = new Random();
string res = "";
for (int i = 0; i < 4; i++)
{
res += s[rnd7.Next(s.Length)];
}
Console.WriteLine(res);
方式2:通过ASCII码生成字母(专业写法)
小写字母 a-z ASCII范围:97 ~ 122
Next(97,123) 包含97,不包含123,刚好覆盖所有小写字母
cs
Random rnd8 = new Random();
string res1 = "";
for (int i = 0; i < 4; i++)
{
// 数字强转为char字符
res1 += (char)rnd8.Next(97, 123);
}
Console.WriteLine(res1);
四、GUID 全局唯一标识符(真正唯一)
1. 概念
GUID(Globally Unique Identifier)全球唯一标识符。
根据:系统时间 + 硬件ID + 算法 生成128位唯一值,几乎不会重复。
2. 格式
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
由 0-9、a-f 组成的32位十六进制数
3. 使用场景
订单号、产品秘钥、文件唯一ID、数据库唯一标识
4. 代码使用
cs
Console.WriteLine(Guid.NewGuid());
// 示例结果:f4ea33ed-8e52-462e-8d3a-620e38f3f91b
五、RNGCryptoServiceProvider 加密级随机数(安全随机)
1. 特点
Random是伪随机(可预测),安全性低;
RNGCryptoServiceProvider 是加密级随机数,不可预测,用于密码、秘钥等高安全场景。
cs
// 创建加密随机对象
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// 创建长度为10的字节数组容器
byte[] bs = new byte[10];
// 填充随机字节数据
rng.GetBytes(bs);
// 字节数组转字符串输出
Console.WriteLine(BitConverter.ToString(bs));
六、三种随机方式对比总结(必背)
| 随机方式 | 随机性 | 安全性 | 使用场景 |
|---|---|---|---|
| Random | 伪随机,种子可控 | 低,可预测 | 抽奖、点名、普通验证码 |
| GUID | 全局唯一 | 极高 | 订单ID、唯一标识、秘钥 |
| RNGCryptoServiceProvider | 加密真随机 | 最高,不可预测 | 密码加密、安全令牌、付费秘钥 |
七、终极易错点总结
-
Random对象绝对不能写在循环内部,否则随机数全部重复
-
种子相同 → 随机数序列一定相同
-
Next(最小值,最大值):含左不含右
-
普通Random不安全,密码相关必须用加密随机或GUID