2011-01-25 4 views
6

だから、私は最初に思ったものから、C#で簡単な方法を書いてきました。 このstaticメソッドは、単純なパスワードの提案発生器として使用されることを意味し、コードは次のようになりますされています私の静的なC#関数は私とゲームをしています... totaly weird!

public static string CreateRandomPassword(int outputLength, string source = "") 
{ 
    var output = string.Empty; 

    for (var i = 0; i < outputLength; i++) 
    { 
    var randomObj = new Random(); 
    output += source.Substring(randomObj.Next(source.Length), 1); 
    } 

    return output; 
} 

私はこのように、この関数を呼び出します。ほとんど常に

var randomPassword = StringHelper.CreateRandomPassword(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); 

さて、この方法"AAAAAA"、 "BBBBBB"、 "888888"などのランダムな文字列を返します。 "A8JK2A"、 "82mOK7"などの文字列を返すべきだと思ったところです。

しかしここではwierd部分です。私がブレークポイントを配置し、行ごとにこの繰り返しを実行すると、正しいタイプのパスワードが返されます。他のケースの100%で、私がデバッグしていないときには、 "AAAAAA"、 "666666"などのような駄目です。

これはどうやって可能ですか?どんな提案も大歓迎です! :-)

私のシステム:Visual Studio 2010、C#4.0、ASP.NET MVC 3 RTMプロジェクト、ASP.NET開発サーバー。他の環境でこのコードをテストしていない。

+0

問題が発生しているかどうかはわかりませんが、各繰り返しで新しいインスタンスのランダムを作成する必要はありません。ループの前に一度これを行う必要があります。 Randomのデフォルトコンストラクタは、Environment.TickCountをシードとして使用します。また、空の文字列が部分文字列の呼び出しに失敗すると思うので、sourceのデフォルト値はあまり意味がありません。 –

+0

あなたは正しいです、パテ氏!当初、文字列「ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890」が配置されていました。ありがとう! – CoderBang

答えて

15

ループ外のrandomObjの宣言を移動します。あなたがそれをデバッグしているとき、シードが異なるために十分な時間差があるので、毎回新しいシードでそれを作成します。しかし、デバッグしていないときは、ループの繰り返しごとにシード時間が基本的に同じになるため、毎回同じ開始値が与えられます。

これは文字列ではなくStringBuilderを使用するのがよいので、文字列に文字を追加するたびにメモリ空間を再初期化する必要はありません。このようなつまり

、:

public static string CreateRandomPassword(int outputLength, string source = "") 
{ 
    var output = new StringBuilder(); 
    var randomObj = new Random(); 
    for (var i = 0; i < outputLength; i++) 
    { 
    output.Append(source.Substring(randomObj.Next(source.Length), 1)); 
    } 
    return output.ToString(); 
} 
+0

ああ、それはそれを説明する!ありがとうKen! :) – CoderBang

+0

個人的に私は、char [](StringBuilderの代わりに)に行き、ソースからインデクサーを介してcharをかき集めましたが、かなり似ていました。 –

+2

+1。もう一つの注意点は、ランダムオブジェクトを可能な限り小さなものとして宣言することが、ほとんど常に良いことです。私は静的なフィールドに宣言を抽出する限りまで行くだろう。この機能に2つのスレッドが同時に当たった場合、まったく同じパスワードが吐き出される可能性があります。 – Rob

4

Randomがあるので、あなたが見ている動作です時間ベース、およびデバッグしていないとき、それは同じで、すべての5回の反復を飛行瞬間(多かれ少なかれ)。同じ種子から最初の乱数を求めています。あなたがデバッグしているときは、毎回新しいシードを取得するのに十分な時間がかかります。

はループの外 Randomの宣言を移動し

:あなたはは、同じランダムシードから1歩動いランダムシードの代わりに、から5歩前進している今

var randomObj = new Random(); 
for (var i = 0; i < outputLength; i++) 
{ 
    output += source.Substring(randomObj.Next(source.Length), 1); 
} 

5回

2

時間依存の新しいシードを含むループを介して、各反復でRandom()の新しいインスタンスをインスタンス化しています。システムクロックの精度と現代のCPUの速度を考えると、これにより、同じシードで何度も擬似ランダムシーケンスを何度もやり直すことが保証されます。あなたはシングルスレッドなら、あなたは安全にロックを省略することができますが

は)(、以下のようなものを試してみてください:

private static Random randomBits = new Random() ; 
public static string CreateRandomPassword(int outputLength, string source = "") 
{ 
    StringBuilder sb = new StringBuilder(outputLength) ; 
    lock (randomBits) 
    { 
    while (sb.Length < outputLength) 
    { 
     sb.Append(randomBits.Next(source.Length) , 1) ; 
    } 
    } 
    return sb.ToString() ; 
} 

あなたは一度だけRNGをインスタンス化します。 Everyは同じRNGのビットを描画するので、エントロピーのソースのように動作するはずです。テストの再現性が必要な場合は、ランダムコンストラクタのオーバーロードを使用して、シードを指定します。同じシード==同じ擬似ランダムシーケンス。

関連する問題