C#使用库时生成随机数,使用内部随机实例

时间:2016-08-23 10:58:03

标签: c# random

为了确保不同的随机数,您应该只使用Random类的一个实例,如答案hereherehere中所述。< / p>

在我的库中,我需要随机数,因此我创建了一个类Randomizer,它提供了使用单个Random实例返回随机数的方法。以下是Randomizer代码的片段:

class Randomizer
{
    private Randomizer() { }
    public static Randomizer Instance { get; } = new Randomizer();

    private static readonly Random random = new Random();
    private static readonly object syncLock = new object();

    public int Next(int minValue, int maxValue)
    {
        lock(syncLock)
        {
            return random.Next(minValue, maxValue);
        }
    }

    // rest of code
}

现在,如果我的图书馆用户还需要随机数,该怎么办?我应该公开我的Randomizer类并在库的文档中指定,用户应该使用我的Randomizer类来生成随机数吗?

4 个答案:

答案 0 :(得分:2)

  

为了确保不同的随机数,您应该只使用一个Random类的一个实例

那不太对劲。创建Random的多个实例是完全没问题的,只要你没有在紧密循环中初始化它们(因为它们是按当前时间播种的,所以你希望每个实例的时间不同。实例化的要点)。

当你创建一个只创建一个Random对象并重用它的静态类时,这很好。从理论上讲,您的库的调用者可以创建自己的静态Random,这些静态window.open('http://YOUR_HOST/develop_tsurumaru/assets/uploads/LJTD2508.xlsx', '_blank'); 可以同时创建,因此它们的生成器会获得与您相同的种子,因此随机数相同。由于创建静态类所花费的时间,可能不会发生。它也可能无论如何都不重要,除非有一个理由说明调用者的序列和你的序列之间的相关性很重要。

答案 1 :(得分:0)

为什么要用自己的实现来增加库的消费者的负担?

如果它是内部的,因为你需要一个非常特定的随机提供程序来处理你的库的内部工作。如果外部消费者在与您的库交互时也不需要遵守您在代码中强加的规则,那么请不要公开您的生成器,并让用户在需要时使用他自己的Random

另一方面,如果您需要消费者在与图书馆的公共API交互时使用您的特定随机生成器,那么您需要公开公开该类。

答案 2 :(得分:0)

使用保证随机的显式种子初始化Random对象(例如,从操作系统获取一个)。这样,用户是否创建自己的Random实例并不重要,您无需考虑使用用户代码同步Next方法的调用。

但是,如果您无法获得随机种子,一种解决方案是定义一个接口,让您的库用户向每个需要随机数的组件注入一个实例:

public interface IRandomizer
{
    int Next(int minValue, int maxValue);
}

此接口的合同必须定义库的确切需求(例如,Next方法必须是线程安全的)。 您的Randomizer类可以实现此接口以用作默认实现。

例如,密钥生成器库组件可以提供两个构造函数:

public class KeyGenerator
{
    private IRandomizer randomizer;

    public KeyGenerator(IRandomizer randomizer) 
    {
        // instance will use the specified IRandomizer
        this.randomizer = randomizer;
    }

    public KeyGenerator()
    {
        // instance will use your Randomizer class.
        this.randomizer = Randomizer.Instance;
    }
}

通过这种方式,您图书馆的用户可以决定是否要提供自己的随机数生成器或使用您库的默认值。

答案 3 :(得分:0)

我使用以下方法:

public interface IRandomizer
{
    int Next(int inclusiveLower, int exclusiveOuter);
}

然后我公开了一个带有默认实现的静态类,并且可选择一个工厂方法来创建特定的&#34;种子&#34;实例。请注意,内部使用的生成器(Default)是公开可访问的,但它完全可以仅仅是内部的:

//Note, the following code is an outline of the general idea

public static class RandomGenerator
{
    private readonly static Lazy<Randomizer> inner = new Lazy<Randomizer>();
    public static IRandomizer Default { get { return inner.Value; } }

    public static IRandomizer CreateNew(Random seed)
    {
        return new Randomizer(seed);
    }

    private class Randomizer : IRandomizer
    {
        private readonly Random random;
        private readonly object syncLock = new object();

        public Randomizer(Random seed = null)
        {
            random = seed ?? new Random();
        }

        public int Next(int minValue, int maxValue)
        {
            lock (syncLock)
            {
                return random.Next(minValue, maxValue);
            }
        }
    }
}