控制台應用中「按鍵隨機顯示預設內容」是典型的隨機數應用場景。本文從Random類核心用法、數組索引邏輯、線程安全陷阱、擴展設計四個維度,提供完整解決方案。
static void Main(string[] args) {
// 1. 預設數據源
string[] items = { "大獎", "二獎", "三獎", "安慰獎", "謝謝參與" };
// 2. 隨機數生成器(單例模式避免種子重複)
Random rand = new Random();
Console.WriteLine("按任意鍵抽獎,ESC退出...");
while (true) {
var key = Console.ReadKey(true); // true=不顯示按鍵字符
if (key.Key == ConsoleKey.Escape) break;
// 3. 生成合法索引:0 到 Length-1
int index = rand.Next(items.Length);
// 4. 顯示結果
Console.WriteLine($"\n恭喜獲得:{items[index]}");
Console.WriteLine("按任意鍵繼續,ESC退出...");
}
}
maxValue必須>0,否則拋出ArgumentOutOfRangeExceptionrand.Next(arr.Length)產生0~Length-1// ❌ 錯誤:短時間內多次實例化,種子相同(默認Environment.TickCount)
while (true) {
Random r = new Random(); // 危險!
Console.WriteLine(r.Next(100));
}
// ✅ 正確:類級靜態單例或方法外實例化
static readonly Random _rand = new Random(); // 或 ThreadLocal
static void Main() { ... _rand.Next() ... }
// 並發場景下內部種子數組競爭導致性能下降或結果偏差
// 解決方案:ThreadLocal 或 .NET 6+ Random.Shared
static readonly ThreadLocal _localRand = new ThreadLocal(() => new Random());
// 使用
int value = _localRand.Value.Next(100);
public interface IRaffleService {
T Draw();
void AddItem(T item, double weight = 1.0); // 支持權重
}
public class WeightedRaffleService : IRaffleService {
private readonly List<(T Item, double Weight)> _items = new();
private readonly Random _rand = Random.Shared; // .NET 6+ 靜態線程安全實例
public void AddItem(T item, double weight = 1.0) {
if (weight <= 0) throw new ArgumentException("權重必須>0");
_items.Add((item, weight));
}
public T Draw() {
if (_items.Count == 0) throw new InvalidOperationException("獎池為空");
// 加權隨機算法:前綴和 + 二分查找 O(log n)
double totalWeight = _items.Sum(x => x.Weight);
double point = _rand.NextDouble() * totalWeight;
double accum = 0;
foreach (var (item, weight) in _items) {
accum += weight;
if (point <= accum) return item;
}
return _items[^1].Item; // 浮點誤差兜底
}
}
// 使用示例
var raffle = new WeightedRaffleService();
raffle.AddItem("特等獎", 0.01);
raffle.AddItem("一等獎", 0.05);
raffle.AddItem("參與獎", 0.94);
for (int i = 0; i < 10; i++) {
Console.WriteLine(raffle.Draw());
}
| 場景 | 技術方案 | 關鍵點 |
|---|---|---|
| 加權抽獎 | 前綴和+二分查找 / 別名法 | 權重歸一化、浮點精度 |
| 不重複抽取 | Fisher-Yates洗牌算法 | O(n)預處理,O(1)抽取 |
| 加密安全隨機 | System.Security.Cryptography.RandomNumberGenerator | 彩票、密鑰生成必須使用 |
| 分布式一致性抽獎 | Redis Lua腳本 / 一致性哈希 | 原子性、防作弊 |
C#隨機抽取的核心是Random.Next(arr.Length)獲取合法索引。生產環境需注意:單例Random、線程安全、業務邏輯與隨機源分離。掌握加權、不重複、加密安全等進階模式,能應對從簡單控制台遊戲到分布式營銷系統的全谱系需求。