ランダム サンプリングと潜在的な問題について一言:
Random クラスには、乱数の一意のシーケンスを生成する機能にいくつかの制限があります。ドキュメントの備考セクションを参照してください。
- 具体的には、Random の既定のコンストラクターはシステム クロックに基づくシードで初期化されるため、Random インスタンスの初期化が非常に迅速に繰り返されると、シーケンスが繰り返される可能性があります。以前に参照された「備考」セクションには、この問題を示すコードが含まれています。
- Random クラス インスタンスのメソッドの呼び出しは、スレッド セーフであるとは限りません。そのため、シードの問題を回避するために Random の単一のインスタンスを使用すると、他のスレッドの問題が発生する可能性があります。
Guid.NewGuid メソッドを使用してセットをサンプリングすると、連続して呼び出された場合にシーケンスが繰り返されないため、ランダムな順序を生成するためのより良い結果が得られます。ただし、いくつかの注意事項があります。
- ランダムセレクターとしてカイ 2 乗テストでうまく機能しますが、暗号化の目的には適しておらず、実際の乱数ジェネレーターの直接の代替にもなりません。
- NewGuid によって生成される GUID がバージョン 4 の GUID である限り、GUID にはランダムなコンテンツが含まれます。ただし、これは将来変更される可能性があります。Microsoft は、GUID にランダムなコンテンツが含まれることを保証する声明を出していません。GUID が一意であり、衝突の可能性が非常に低いというだけです。
NewGuid を使用すると、次のようになります。
string[] myRandomArray = choices.OrderBy(x => Guid.NewGuid()).Take(3).ToArray();
RNGCryptoServiceProvider クラスを使用することは、信頼できるランダム サンプリングを生成するための最良のソリューションです。スレッド セーフであり、ランダム クラスが持つシード問題の影響を受けません。ただし、実装するにはさらに多くのコードが必要です。
// TODO: Add code to demonstrate using RNGCryptoServiceProvider
既に LINQ を使用しているため、For ループではなく take を使用できます。
// Get 3 random choices in a List.
List<string> myChoices = choices.OrderBy(x => Guid.NewGuid()).Take(3).ToList();
// Add the correct answer.
myChoices.Add(theAnswer);
// Randomize the resulting set of 4 choices into an Array.
string[] myRandomizedChoices = myChoices.OrderBy(x => Guid.NewGuid()).ToArray();
this.radioButton1.Text = myRandomizedChoices[0];
this.radioButton2.Text = myRandomizedChoices[1];
this.radioButton3.Text = myRandomizedChoices[2];
this.radioButton4.Text = myRandomizedChoices[3];