我想要一个永远独一无二的数字,我想出了以下代码, 它生成一个数字并在其末尾添加一个校验位,我想知道这段代码有多可靠?
public void GenerateUniqueNumber(out string ValidUniqueNumber) {
string GeneratedUniqueNumber = "";
// Default implementation of UNIX time of the current UTC time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
string FormatedDateTime = Convert.ToInt64(ts.TotalSeconds).ToString();
string ssUniqueId = DateTime.UtcNow.ToString("fffffff");
//Add Padding to UniqueId
string FormatedUniqueId = ssUniqueId.PadLeft(7, '0');
if (FormatedDateTime.Length == 10 && FormatedUniqueId.Length == 7)
{
// Calculate checksum number using Luhn's algorithm.
int sum = 0;
bool odd = true;
string InputData = FormatedDateTime + FormatedUniqueId;
int CheckSumNumber;
for (int i = InputData.Length - 1; i >= 0; i--)
{
if (odd == true)
{
int tSum = Convert.ToInt32(InputData[i].ToString()) * 2;
if (tSum >= 10)
{
string tData = tSum.ToString();
tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
}
sum += tSum;
}
else
sum += Convert.ToInt32(InputData[i].ToString());
odd = !odd;
}
//CheckSumNumber = (((sum / 10) + 1) * 10) - sum;
CheckSumNumber = (((sum + 9) / 10) * 10) - sum;
// Compute Full length 18 digit UniqueNumber
GeneratedUniqueNumber = FormatedDateTime + FormatedUniqueId + Convert.ToString(CheckSumNumber);
}
else
{
// Error
GeneratedUniqueNumber = Convert.ToString(-1);
}
ValidUniqueNumber = GeneratedUniqueNumber;
}
编辑:澄清 无法使用GUID,需要通过电话键盘将数字输入IVR系统。
答案 0 :(得分:6)
您不能使用GUID,但您可以创建与GUID类似的唯一编号的own格式,该格式基于机器的MAC地址(空格)以及当前时间和日期(时间)。如果机器都具有同步时钟,则保证这是唯一的。
有关详细信息,请参阅here
答案 1 :(得分:5)
为什么不使用Guid
?
答案 2 :(得分:4)
此方法存在一些问题:
你基本上只计算从1970年1月1日开始的毫秒数。你可以从ts.TotalSeconds
四舍五入到0.0000001。您的所有转换和毫秒计算都是不必要的。
10年约为3×10 11毫秒。您保留了17位有效数字,因此在接下来的10年中,前5位数字将永远不会改变,也不能用于区分数字。它们毫无用处。
您是否在1970年至今之间生成毫秒数?如果没有,它们也不能用来区分数字而且没用。
这完全取决于什么机器返回日期。有权访问此计算机的任何人都可以生成他们想要的任何“唯一”数字。这是问题吗?
任何看到其中一个号码的人都可以知道它何时生成。这是一个问题吗?
任何人都可以预测何时生成的数字。这是一个问题吗?
10 15 毫秒大约是30000年。之后,您的算法将重复数字。似乎很长一段时间,但你指定“永远”,而30000年不是“永远”。你的意思是“永远”吗?
答案 3 :(得分:3)
如果我正确理解您的实现,它只使用当前日期/时间作为基础。这意味着如果您同时创建两个ID,它们将不是唯一的。
答案 4 :(得分:1)
由于您(在评论中)提到ID存储在数据库中,您可以使用您提到的方法或随机生成ID,并检查数据库中是否存在。
如果它已经存在,请生成一个新的,否则你就完成了。
但有一点,我会确保在事务中检查是否存在ID以及将记录实际保存到数据库中,否则您将面临另一个请求创建该记录的风险。检查ID和行的创建。
同样只是检查,为什么数据库本身生成的自动增量号不起作用?数据库将保证它的唯一性(无论如何,对于该表)
答案 5 :(得分:1)
您没有说明这些数字的用途。他们是否有某种与他们相关的价值?如果用户能够找出方案并猜出有效的票号,会不会有问题?
如果难以猜测这些数字很重要,那么这个方案就会失败;输出看起来非常随机的数据的东西会更好。您可以采用单调递增的序列号并使用块密码(具有64位块大小)对其进行加密;这给你一个64位输出或大约20个十进制数字值,你可以采取(比如说)最后18位。 (如果可逆性很重要,即给定一个票号以便你能够恢复序列号,你需要在这里更加小心。)
您是否需要铸铁100%保证没有门票号码相同?如果是这样,您需要将它们保存在数据库中并在使用时将其标记为关闭。如果你这样做,那么每次使用一个好的随机数发生器并检查欺骗可能是合理的。
答案 6 :(得分:1)
使用系统时间是一个很好的开始,但如果您需要同时生成两个UID,它会给您带来冲突。你使用“fffffff”格式没有任何帮助:Windows时钟分辨率只有15-16毫秒,所以只有一两个“f”在做任何好事。
此外,您的方法会告诉您何时生成ID。根据您的需要,这可能是一个理想的功能,或者可能存在安全风险。
除了时间之外,您还需要使用您的ID来包含其他信息。一些可能的选择是:
如果您想确保唯一性,请将您的ID存储在数据库中,以便检查重复项。
答案 7 :(得分:0)
正如“Andrew Hare”所说,你可以使用Guid。 关于你的代码答案是“不”! 因为如果客户的计算机的DateTime错误或更改结果可能是几个或更多!
答案 8 :(得分:-1)
无论如何都没有随机的东西。这是一个建议。