订单编号一个重要需求是避免重复,还有是尽量短,利于用户输入,以下分享一个C#编写的类,使用时用单例模式,或者设置全局静态变量。上代码吧
public class OrderCodeGenerator : IDisposable
{
Dictionary<string, Queue<string>> orderNosByDay = new();
int Lenght;
public OrderCodeGenerator(int lenght)
{
//号码池规模与Lenght相关,等于10的lenght次方,在Init()中体现
Lenght = lenght;
Recover();
}
/// <summary>
/// 生成订正式订单编号
/// </summary>
/// <param name="prefix">自定义前缀</param>
/// <returns></returns>
public string Generate(string prefix="")
{
var key = GetKey();
//日期部分,避免重估
var dayPart = DateTime.Now.ToString("yyyyMMdd");
var code = "";
lock (orderNosByDay)
{
if (!orderNosByDay.ContainsKey(key))
{
Recover();
}
code = prefix + dayPart + orderNosByDay[key].Dequeue();
}
Persist();
return code;
}
string GetFilePath()
{
var dir = Path.Combine(Environment.CurrentDirectory, "temp");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var key = GetKey();
return Path.Combine(dir, key + ".txt");
}
string GetKey()
{
return DateTime.Now.ToString("yyyyMMdd");
}
/// <summary>
/// 持久化到文件
/// </summary>
void Persist()
{
var key = GetKey();
using (var fs = File.CreateText(GetFilePath()))
{
if (orderNosByDay.ContainsKey(key))
{
foreach (var item in orderNosByDay[key])
{
fs.WriteLine(item);
}
}
}
}
/// <summary>
/// 从持久化文件恢复,如果没有则初始化
/// </summary>
void Recover()
{
var filePath = GetFilePath();
var key = GetKey();
var _queue = new Queue<string>();
if (File.Exists(filePath))
{
using (var fs = File.OpenText(filePath))
{
string line = "";
while (!string.IsNullOrEmpty(line = fs.ReadLine()))
{
_queue.Enqueue(line?.Trim());
}
orderNosByDay[key] = _queue;
}
}
else
{
Init();
Persist();
}
}
/// <summary>
/// 初始化无重复订单号码池并打乱顺序
/// </summary>
void Init()
{
var size = (int)Math.Pow(10, Lenght);
var numbers = new List<string>();
for (int i = 0; i < size; i++)
{
numbers.Add(i.ToString().PadLeft(Lenght, '0'));
}
var key = GetKey();
orderNosByDay[key] = new Queue<string>();
Random r = new Random();
while (numbers.Count > 0)
{
var index = r.Next(0, numbers.Count);
var n = numbers[index];
orderNosByDay[key].Enqueue(n);
numbers.RemoveAt(index);
}
}
public void Dispose()
{
Persist();
}
}
使用
static OrderCodeGenerator genrator = new OrderCodeGenerator(4);
string NewOrderId(string prefix="")
{
string orderCode = genrator.Generate(prefix);
return orderCode;
}
lenght=4,保证每日有1w个号码可用,如果想要号码池更大,加大lenght即可。
持久化方式其实可以有多种方式,数据库,redis等等。