Random实例应复用而非频繁new,Next(min,max)返回≥min且

Random 实例不能反复 new
很多人写 new Random() 像呼吸一样自然,但每次 new 都用系统时间当种子,高频调用时(比如循环里)会生成一串重复值。这不是 bug,是设计使然——DateTime.Now.Millisecond 分辨率有限。
正确做法是复用同一个 Random 实例:
- 类成员字段声明:
private readonly Random _rnd = new Random(); - 静态只读实例(多线程需注意):
private static readonly Random _rnd = new Random(); - 若必须线程安全,改用
Random.Shared(.NET 6+):Random.Shared.Next(1, 100)
Next() 的区间是左闭右开,不是数学上的 [a,b]
Next(int min, int max) 返回的是 ≥ min 且 的整数,这点和 Python 的 randint 或 JavaScript 的 Math.floor(Math.random() * (max - min + 1)) + min 都不同。新手常误以为 Next(1, 6) 能出 6,结果永远卡在 1–5。
常见场景对照:
- 掷骰子(1–6)→ 用
rnd.Next(1, 7) - 数组随机索引(0 到
arr.Length - 1)→ 用rnd.Next(0, arr.Length) - 生成 [0, 1) 浮点数 → 用
rnd.NextDouble(),别自己除
Random 不适合密码学或唯一 ID 场景
Random 是伪随机,可预测、不可重现(除非手动传入种子),且不具备密码学安全性。拿它生成 token、盐值、API key,等于把门钥匙刻在玻璃上。
该换就换:
- 需要加密安全随机数 → 改用
RandomNumberGenerator(.NET Core 2.1+):RandomNumberGenerator.GetInt32(1, 100) - 生成唯一 ID → 直接用
Guid.NewGuid(),别绕路 - 需要可重现的随机序列(如游戏存档、测试)→ 显式传种子:
new Random(42)
.NET 6+ 推荐优先用 Random.Shared
静态属性 Random.Shared 是线程安全的共享实例,内部做了锁优化,比自己封装 lock 或 ThreadLocal 更轻量、更可靠。
但要注意两点:
- 它不能传种子,所以不适用于需要可重现随机流的场合
- 如果代码跑在 .NET 5 或更早版本,
Random.Shared不存在,会编译失败 - 跨进程/跨 AppDomain 时仍需自行管理生命周期,Shared 不解决所有并发问题
真要兼容老版本又想要线程安全,不如直接升级目标框架——这比手写同步逻辑省心多了。










