2016-08-23 11 views
0

here,hereおよびhereのように、異なる乱数を確保するには、Randomクラスのインスタンスを1つだけ使用する必要があります。C#乱数を生成するライブラリを使用しているときにランダムなインスタンスを使用する

私のライブラリでは乱数が必要なので、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クラスを使用する必要があるかどうかを指定する必要がありますか?

+3

あなたは、少なくとも乱数が使用されますどのような 'Random'インスタンス –

+1

を取るコンストラクタを提供する必要があります。内部的に使用ジェネレータ(Default)が公にづけしているが、それは完璧にのみ内蔵可能性があることに注意してください? – Jonathan

+0

私は 'Random'インスタンスを取るコンストラクタを提供する場合、私は自分のライブラリのどこかに' Random'インスタンスを作成する必要があります。次に、このインスタンスを返すpublic(ライブラリ外)のプロパティまたはメソッドを作成する必要がありますか?または、ライブラリのユーザが 'Random'インスタンスを作成し、それを' Randomizer'コンストラクタに渡すべきです**他のライブラリクラスのいずれかが使用される前に**? @Matt私はそれを知っていますが、 'Random.Next(int、int)'メソッドでは、2番目の引数はmaxValueとも呼ばれます。 @Jonathan乱数が何らかの指定よりも小さいかどうかをチェックするために使用します値。 – Darko

答えて

2

異なる乱数を確保するために、あなたはかなり右ではありませんランダムクラス

の1つのインスタンスのみを使用する必要があります。タイトなループでそれらをすべて初期化しない限り(現在の時刻でシードされるので、インスタント化の時点でそれぞれの時刻が異なるようにしてください)、Randomの複数のインスタンスを作成するのは問題ありません。 。

ただ1つのRandomオブジェクトを作成して再利用する静的クラスを作成しているので、それは問題ありません。理論的には、あなたのライブラリーの呼び出し側が、同時に作成された独自のスタティックRandomを作成する可能性があります。そのため、ジェネレーターはあなたと同じシードと同じ乱数シーケンスを取得します。そのおそらくは、静的クラスの作成に時間がかかるために発生しません。またおそらくは、発信者のシーケンスとあなたのシーケンスとの間に相関関係がある理由がない限り、とにかく重要ではありません。

0

あなたは自分のライブラリの消費者に自分の実装を負わせているのですか?

あなたのライブラリの内部の動作のために非常に特定のランダムなプロバイダが必要なので、その内部の場合。ライブラリとやりとりするときに外部の消費者がコードに課した規則にも従う必要がない場合は、ジェネレータを公開しないで、必要に応じてユーザに自分自身のRandomを使用させます。

一方、消費者がライブラリのパブリックAPIとやりとりするときに特定のランダムジェネレータを使用する必要がある場合は、そのクラスをパブリックに公開する必要があります。

+0

私の特定のランダムジェネレータをconumerに使用させる必要はありません。しかし、消費者が自分の「ランダム」インスタンスを作成すると、2つの「ランダム」インスタンス(ライブラリと消費者の私の)によって生成される数字は本当にランダムになりますか?私はただ一つの 'ランダム'インスタンス(質問の中のリンクを参照)を使うべきだということを読んだ。 – Darko

+1

@Darko。いいえ、絶対に問題はありません。 [Matthew Strawbridge](http://stackoverflow.com/users/241605/matthew-strawbridge)[answer](http://stackoverflow.com/a/39100001/767890)、ここでは、作成時に発生する可能性のある問題について説明します複数の「ランダム」インスタンス。 – InBetween

0

乱数であることが保証されている明示的なシードを使用してランダムオブジェクトを初期化します(たとえば、オペレーティングシステムから取得するなど)。そうすれば、ユーザが自分自身のランダムインスタンスを作成し、ユーザコードでNextメソッドへの呼び出しを同期させることについて考える必要はありません。

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

契約:

しかし、あなたは、ランダムシードを取得することができない場合は、1つの解決策は、インタフェースを定義し、あなたのライブラリーのユーザーは乱数を必要とする各コンポーネントにインスタンスを注入するようにするだろう(例えば、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; 
    } 
} 

あなたのライブラリーの利用者は、彼が彼自身の乱数ジェネレータを提供したり、あなたのライブラリーのデフォルトを使用するかどうかを決めることができますこの方法:

は、例えば、鍵生成ライブラリコンポーネントは、2つのコンストラクタを提供することができます。

0

私は、次のアプローチを使用したい:

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

そして私は、デフォルトの実装および特定の「播種」のインスタンスを作成するために、必要に応じてファクトリメソッドと静的クラスを公開すると思います。

//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); 
      } 
     } 
    } 
} 
関連する問題