簡體   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