dotnet 10 Random GetString
支持
Intro
.NET 8 里引入了 Random.GetItems
和 RandomNumberGenerator.GetString
/RandomNumberGenerator.GetHexString
.NET 8 Preview 1 中新增的 Random 方法
在 .NET 10 Preview 3 中为 Random 也引入了
GetString
/GetHexString
的支持,基于 Random 的使用更为方便对于简单的使用场景也比使用 RandomNumberGenerator
的性能更好一些
New API
新引入的 API 定义如下,和 RandomNumberGenerator
方法是类似的,只是 RandomNumberGenerator
的方法是 static
的,新增的方法是 Random
中的实例方法 :
namespace System;
public partial class Random
{
// same signatures as on RandomNumberGenerator, but instance instead of static
public string GetString(ReadOnlySpan<char> choices, int length);
public string GetHexString(int stringLength, bool lowercase = false);
public void GetHexString(Span<char> destination, bool lowercase = false);
}
提出 API 的一些描述如下,可以参考 api 提议的 issue:https://github.com/dotnet/runtime/issues/111956
我们为 RandomNumberGenerator 添加了 GetString 和 GetHexString 方法。Random 没有这些方法,但它们在这里同样有用。这些方法与加密安全性并没有太多特定的关系。开发人员需要通过使用 string.Create 然后调用 Random.GetItems 来填充后备空间。如果简单的重载对于 RandomNumberGenerator 是合理的,那么它们对 Random 同样适用。
Sample
使用方式和 RandomNumberGenerator
基本一致
Console.WriteLine("GetString");
var nums = "1234567890";
var randomString = Random.Shared.GetString(nums, 8);
Console.WriteLine(randomString);
Console.WriteLine("GetHexString");
var randomHexString = Random.Shared.GetHexString(16);
Console.WriteLine(randomHexString);
Console.WriteLine(Random.Shared.GetHexString(16, true));
Console.WriteLine("GetHexString Span");
Span<char> chars = stackallocchar[16];
Random.Shared.GetHexString(chars);
Console.WriteLine(chars);
Random.Shared.GetHexString(chars, true);
Console.WriteLine(chars);
如果要在之前的版本里使用,可以使用 RandomNumberGenerator
的 API 来代替
Console.WriteLine("RandomNumberGenerator");
var randString = RandomNumberGenerator.GetString(nums, 8);
Console.WriteLine(randString);
Console.WriteLine(RandomNumberGenerator.GetHexString(16));
Console.WriteLine(RandomNumberGenerator.GetHexString(16, true));
RandomNumberGenerator.GetHexString(chars);
Console.WriteLine(chars);
RandomNumberGenerator.GetHexString(chars, true);
Console.WriteLine(chars);
输出结果如下:
Benchmark
前面我们提到了性能更好,是否真的如此呢,我们可以做一个简单的 benchmark 来测试一下,benchmark 代码如下:
[ShortRunJob]
publicclassBenchmark
{
privatestaticreadonlychar[] Chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
[Benchmark(Baseline = true)]
public string RandomGetString()
{
return Random.Shared.GetString(Chars, 8);
}
[Benchmark]
public string RandomNumberGeneratorGetString()
{
return RandomNumberGenerator.GetString(Chars, 8);
}
}
benchmark 结果如下:
从基准测试结果可以看出,Random
的性能更好,RandomNumberGenerator
的 GetString
方法耗时是 Random
的 1.83
倍
More
为什么 RandomNumberGenerator
比 Random
慢?
1. 加密强度更高 RandomNumberGenerator
(例如RandomNumberGenerator.GetBytes
)基于加密算法(比如 AES 或操作系统提供的 CSPRNG)。这些算法设计目的是不可预测、不可逆、统计上随机,所以它们会消耗更多的 CPU 资源。2. 依赖系统熵源
它通常从系统级熵源读取数据(比如 Linux 的/dev/urandom
或 Windows 的BCryptGenRandom
),这会带来额外的 I/O 和同步开销。3. 线程安全和隔离机制
加密用的 RNG 设计时考虑了线程安全、隔离和防止侧信道攻击,因此增加了锁、上下文校验和其他安全逻辑。4. 不做缓存或简化
和Random
不同,RandomNumberGenerator
每次都从头生成随机数,不复用种子,不做简化,以保证安全性。
什么时候应该使用 RandomNumberGenerator
?
当你需要不可预测的随机数时,就应该使用它。比如:
o 生成密码、API 密钥、Token o 为密码哈希生成盐值 o 生成加密密钥或 IV o 生成安全的 Session ID o 生成 nonce(一次性随机数) o 任何预测 = 漏洞 的情况
总结:如果你的应用场景中,黑客能猜出“随机数”就会出问题,那就用
RandomNumberGenerator
。
什么时候用 Random
更合适?
当你不关心安全,只想要速度快、用法简单时,用 Random
或 .NET 6+ 的 Random.Shared
:
o 游戏机制(比如掷骰子、掉落奖励) o 生成随机颜色或 UI 效果 o 模拟、测试或生成假数据 o 打乱顺序(非安全用途) o 普通的概率判断逻辑
References
o https://github.com/dotnet/runtime/issues/111956 o https://github.com/dotnet/runtime/pull/112162 o https://github.com/WeihanLi/SamplesInPractice/blob/main/net10sample/Net10Samples/RandomSample.cs o .NET 8 Preview 1 中新增的 Random 方法