A New Way to Randomize in .NET 8
We've all used random numbers in C# for various reasons. It has never been difficult to get a random number and use it, we've all probably written something like this:
public int GetRandomNumber(int max)
{
var random = new Random();
return random.Next(max);
}
// Or as a single line
var num = new Random().Next(100);
Easy, simple, and short.
.NET 6 gave us a wonderful new property on the Random class: Shared. Random now comes with a static instance and there is no need to new up a Random ever again. The above code becomes this:
public int GetRandomNumber(int max) => Random.Shared.Next(max);
A one liner that arguably does not need to exist. It would be just as easy to not have that function at all and simply call Random.Shared.Next()
whenever you need a random number.
That's great! But what if what I really want is a random value from a set list of values? Now we need to get a list or array of values and pick one based on a random number. Let's say you have an enum of Colors:
public enum Color {
Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
And that you want to pick one at random:
public Color GetRandomColor()
{
Color[] colors = Enum.GetValues<Colors>();
return colors[Random.Shared.Next(colors.Length - 1)];
}
Not terrible, but what if we need more than 1? Now it's getting ugly:
public List<Color> GetRandomColors(int count)
{
List<Color> results = new List<Color>();
Color[] colors = Enum.GetValues<Colors>();
int max = colors.Length - 1;
for (var i = 0; i < count; i++)
{
results.Add(colors[Random.Shared.Next(max)]);
}
return results;
}
Or even worse, what if we have a list that we need to shuffle?
void ShuffleInPlace<T>(T[] items)
{
var count = items.Length;
for (var i = 0; i < count; i++)
{
var index = Random.Shared.Next(count);
var trade = items[index];
items[index] = items[i];
items[i] = trade;
}
}
All of the above functions are clunky and feel like they shouldn't be necessary. Fortunately, with .NET 8 they no longer are! Random got 2 new functions: GetItems() and Shuffle(). The first two functions become one liners:
var color = Random.Shared.GetItems(Enum.GetValues<Colors>(), 1).Single();
var colors = Random.Shared.GetItems(Enum.GetValues<Colors>(), 25).ToList();
And with Shuffle you can randomize an array or a span in place in a single line of code:
var colors = Random.Shared.GetItems(Enum.GetValues<Colors>(), 25);
Random.Shared.Shuffle(colors);
I love these new functions and I'm looking forward to using them. What do you think? Are these useful or bloat? Can you think of another practical use for randomizing a group of objects?