Random
Programs often need to generate random data. An ID or user name could be based on random data. The Random
class
in C# helps here—it is easy to use and fast.
For using the Random
class
, the important part to remember is that you should create the class
once. Then reuse it to get a random stream of numbers.
Random
class
Random
, a class
, is available when we include (or reference) the System
namespace. We use Random
and Next()
with 2 arguments.
Next()
is the inclusive minimum number allowed by the random number generator.using System; // ... Create new Random object. Random random = new Random(); // ... Get 3 random numbers. // These are always 5, 6, 7, 8 or 9. Console.WriteLine(random.Next(5, 10)); Console.WriteLine(random.Next(5, 10)); Console.WriteLine(random.Next(5, 10));6 5 9
A static
thing only has one instance. A static
Random
improves programs. Here the Random
object is stored as a static
variable. Methods that use it will still get good random ints.
UseStatic
method 2 times in the Main
method. Each call uses the same Random
instance.UseStatic
, we reference the static
Random
instance, and call Next()
on it. We print the random number.Random
at the method level as a local, a problem would arise. The time-dependent seed would repeat itself.using System; class Program { static void Main() { // Part 1: call a method that uses class-level Random. UseStatic(); // Call the same method. // ... The random number sequence will still be random. UseStatic(); } static Random _random = new Random(); static void UseStatic() { // Part 2: use class-level Random. // ... When this method is called many times, it still has good Randoms. int result = _random.Next(); // If this method declared a local Random, it would repeat itself. Console.WriteLine("STATIC RANDOM: " + result); } }STATIC RANDOM: 810380956 STATIC RANDOM: 123622001
This is a bad example of code—do not use it in a real program. When we create a Random
object, its seed is based on the time.
Random
objects at the same time (or close in time) our random numbers will repeat.Random
as an argument to avoid repeated random numbers.class Program { static void Main() { Test(); Test(); Test(); } static void Test() { // Create random and use it. // ... This is time-dependent, so can repeat if called many times. var random = new System.Random(); System.Console.WriteLine("CURRENT: " + random.Next()); } }CURRENT: 747025912 CURRENT: 747025912 CURRENT: 747025912
Exception
, minValue
When calling Next()
, be careful that the "minimum value" is lower than the "maximum value." So the first argument is always lower than the second.
using System; class Program { static void Main() { var random = new Random(); // First argument must be lower than the second. int result = random.Next(20, 10); } }Unhandled Exception: System.ArgumentOutOfRangeException: 'minValue' cannot be greater than maxValue. Parameter name: minValue at System.Random.Next(Int32 minValue, Int32 maxValue) at Program.Main()...
Max
Here is another example of the maxValue
parameter on the Next method. When we pass an integer to Random.Next()
, we get a result in the range of 0 to maxValue
minus 1.
Next()
method 2 parameters. The lower bound is inclusive, but the upper one is not.using System; class Program { static void Main() { F(); F(); F(); F(); F(); F(); } static Random _r = new Random(); static void F() { int n = _r.Next(5); // Can return 0, 1, 2, 3, or 4. Console.WriteLine(n); } }2 1 1 0 3 2
Modulo division can be used on random numbers. Here we get 10 random numbers, then use modulo to get an index into a small array. Then we increment random elements.
Next()
that are in the correct range would be better than using modulo, as the code is more direct and simpler.using System; int[] array = new int[3]; var random = new Random(); // Get 10 random numbers, then use modulo to increment array elements. for (int i = 0; i < 10; i++) { int result = random.Next(0, 100); int modulo = result % array.Length; array[modulo]++; } // Display the end result. for (int i = 0; i < array.Length; i++) { Console.WriteLine("ARRAY {0} = {1}", i, array[i]); }ARRAY 0 = 2 ARRAY 1 = 4 ARRAY 2 = 4
string
This example is a bit more complex. It randomizes the chars in a string
. It sorts on a random number to shuffle data.
OrderBy
with a lambda expression.ToArray
converts the enumerable letters in the statement to a string
again, producing the final result: a randomized string
.using System; using System.Linq; // The source string. const string original = "senators"; // The random number sequence. Random num = new Random(); // Create new string from the reordered char array. string rand = new string(original.ToCharArray(). OrderBy(s => (num.Next(2) % 2) == 0).ToArray()); // Write results. Console.WriteLine("original: {0}\r\nrand: {1}", original, rand);original: senators rand: tossenar
You can also call the NextBytes
method on the Random
type to acquire a random byte
array. Each byte
has the decimal range of 0 to 255.
NextBytes
method allows you to get a random value of arbitrary length in one method invocation.NextBytes
to get much more random data at once.using System; class Program { static void Main() { // Put random bytes into this array. byte[] array = new byte[8]; // Use Random class and NextBytes method. // ... Display the bytes with the following method. Random random = new Random(); random.NextBytes(array); Display(array); random.NextBytes(array); Display(array); } static void Display(byte[] array) { // Loop through and display bytes in the array. foreach (byte value in array) { Console.Write(value); Console.Write(' '); } Console.WriteLine(); } }177 209 137 61 204 127 103 88 167 246 80 251 252 204 35 239
RNGCryptoServiceProvider
The Random
class
is not as random as possible—do not use it for cryptography. For cryptography in .NET, use the RNGCryptoServiceProvider
class
.
RNGCryptoServiceProvider
with a using statement.byte
array of 10 elements. Then we call GetBytes()
to populate it with random data.foreach
-loop and the Console.Write
method to print out all of our random data.using System; using System.Security.Cryptography; // Step 1: create object. using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) { // Step 2: create and fill buffer. var data = new byte[10]; rng.GetBytes(data); // Step 3: display random bytes. foreach (var d in data) { Console.Write(d); } Console.WriteLine(); }1261711625221018917915387232
RandomNumberGenerator
Using RNGCryptoServiceProvider
is obsolete and causes a warning when compiled. Instead, in .NET 7, we can use the RandomNumberGenerator
static
class
and invoke Create.
RandomNumberGenerator.Create()
in a using statement to create the required object.RNGCryptoServiceProvider
directly, we can use GetBytes()
and pass an empty byte
array.byte
array buffer by GetBytes
.using System; using System.Security.Cryptography; // Step 1: create object with static method. using (var rng = RandomNumberGenerator.Create()) { // Step 2: create buffer and call GetBytes on it to fill it. var temp = new byte[8]; rng.GetBytes(temp); // Step 3: print out the bytes. foreach (var b in temp) { Console.Write(b); } Console.WriteLine(); }106851631498298176114
Suppose we want many random ints, but having high-quality random numbers is not important. We can pre-populate a List
with random ints.
Random.Next
.Random.Next
method to get random ints.List
element access of precomputed random ints. This approach might work in some programs.static
list and avoid the startup time cost.using System; using System.Collections.Generic; using System.Diagnostics; class Program { static Random _random = new Random(); static List<int> _randomCache = new List<int>(); static void AddRandoms() { // Add random numbers to a list for later use. for (int i = 0; i < 1000; i++) { _randomCache.Add(_random.Next()); } } const int _max = 10000000; static void Main() { // Precompute some random ints. AddRandoms(); // Version 1: get new random int. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { int random = _random.Next(); if (random < 0) { return; } } s1.Stop(); // Version 2: use cached random int from list. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { int random = _randomCache[i % _randomCache.Count]; if (random < 0) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } }8.93 ns Random.Next() 2.79 ns Random Cache (List)
Be careful of creating new Randoms—the results may start to repeat. Instead, reusing the same Random
is a more ideal approach to pseudo-random number generation in C#.