繁体   English   中英

C#在使用库时生成使用内部Random实例的随机数

[英]C# Generate random numbers, while using library, that use internal Random instance

为了确保不同的随机数,您应该仅使用Random类的一个实例,如此此处此处的答案所建议。

在我的库中,我需要随机数,因此我创建了一个类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类来生成随机数吗?

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

那不是很正确。 创建多个Random实例非常好,只要您不要在紧凑的循环中初始化它们(因为它们是在当前时间播种的,因此您希望实例化时每个实例的当前时间都不同) 。

当您创建一个仅创建一个Random对象并重用它的静态类时,就可以了。 从理论上讲,您的库的调用者可以创建自己的静态Random ,该静态Random是同时创建的,因此它们的生成器将与您的生成器获得相同的种子,并因此获得相同的随机数序列。 由于创建静态类需要花费时间,因此可能不会发生。 除非有一定的原因,否则在呼叫者的序列和您的序列之间的相关性重要,反正这也可能无关紧要。

您为什么要用自己的实现负担图书馆的使用者?

如果它是内部的,因为您需要一个非常特定的随机提供程序来提供库的内部运行。 如果在与库交互时不需要外部使用者也遵守您在代码中强加的规则,则不要公开生成器,如果需要的话,让用户使用自己的Random

另一方面,如果您需要使用者在与库的公共API交互时使用特定的随机数生成器,则需要公开公开该类。

通过使用保证为随机的显式种子(例如,从操作系统中获取一个)来初始化您的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;
    }
}

这样,您的图书馆用户就可以决定是要提供自己的随机数生成器,还是要使用图书馆的默认值。

我将使用以下方法:

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

然后,我将公开一个带有默认实现的静态类,以及一个可选的工厂方法,以创建特定的“种子”实例。 请注意,内部使用的生成器( 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);
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM