解决 args 变量没有赋值导致的参数传递失败的问题。by Soar360
大石头 编写于 2023-09-09 07:16:48
X
using System;
using System.Security.Cryptography;
using System.Text;
using NewLife.Collections;

namespace NewLife.Security;

/// <summary>随机数</summary>
public static class Rand
{
    private static readonly RandomNumberGenerator _rnd;

    static Rand() => _rnd = new RNGCryptoServiceProvider();

    /// <summary>返回一个小于所指定最大值的非负随机数</summary>
    /// <param name="max">返回的随机数的上界(随机数不能取该上界值)</param>
    /// <returns></returns>
    public static Int32 Next(Int32 max = Int32.MaxValue)
    {
        if (max <= 0) throw new ArgumentOutOfRangeException(nameof(max));

        return Next(0, max);
    }

    [ThreadStatic]
    private static Byte[] _buf;
    /// <summary>返回一个指定范围内的随机数</summary>
    /// <remarks>
    /// 调用平均耗时37.76ns,其中GC耗时77.56%
    /// </remarks>
    /// <param name="min">返回的随机数的下界(随机数可取该下界值)</param>
    /// <param name="max">返回的随机数的上界(随机数不能取该上界值)</param>
    /// <returns></returns>
    public static Int32 Next(Int32 min, Int32 max)
    {
        if (max <= min) throw new ArgumentOutOfRangeException(nameof(max));

        _buf ??= new Byte[4];
        _rnd.GetBytes(_buf);

        var n = BitConverter.ToInt32(_buf, 0);
        if (min == Int32.MinValue && max == Int32.MaxValue) return n;
        if (min == 0 && max == Int32.MaxValue) return Math.Abs(n);
        if (min == Int32.MinValue && max == 0) return -Math.Abs(n);

        var num = max - min;
        // 不要进行复杂运算,看做是生成从0到(max-min)的随机数,然后再加上min即可
        return (Int32)((num * (UInt32)n >> 32) + min);
    }

    /// <summary>返回指定长度随机字节数组</summary>
    /// <remarks>
    /// 调用平均耗时5.46ns,其中GC耗时15%
    /// </remarks>
    /// <param name="count"></param>
    /// <returns></returns>
    public static Byte[] NextBytes(Int32 count)
    {
#if NET6_0_OR_GREATER
    return RandomNumberGenerator.GetBytes(count);
#elif NETFRAMEWORK || NETSTANDARD2_0
        return new Random().NextBytes(count);
#else
    var buf = new Byte[count];
    RandomNumberGenerator.Fill(buf);
    return buf;
#endif
    }

#if NETFRAMEWORK || NETSTANDARD2_0
    /// <summary>
    /// 返回随机数填充的指定长度的数组
    /// </summary>
    /// <param name="random"></param>
    /// <param name="length">数组长度</param>
    /// <returns>随机数填充的指定长度的数组</returns>
    private static Byte[] NextBytes(this Random random, Int32 length)
    {
        if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));

        var data = new Byte[length];
        random.NextBytes(data);
        return data;
    }
#endif

    /// <summary>返回指定长度随机字符串</summary>
    /// <param name="length">长度</param>
    /// <param name="symbol">是否包含符号</param>
    /// <returns></returns>
    public static String NextString(Int32 length, Boolean symbol = false)
    {
        var sb = Pool.StringBuilder.Get();
        for (var i = 0; i < length; i++)
        {
            var ch = ' ';
            if (symbol)
                ch = (Char)Next(' ', 0x7F);
            else
            {
                var n = Next(0, 10 + 26 + 26);
                if (n < 10)
                    ch = (Char)('0' + n);
                else if (n < 10 + 26)
                    ch = (Char)('A' + n - 10);
                else
                    ch = (Char)('a' + n - 10 - 26);
            }
            sb.Append(ch);
        }

        return sb.Put(true);
    }
}