There seems to be some confusion in this post about how the Random class works and about the lock statement.
I hope to clear the waters a little with this answer.
First let's replicate the problem:
private void Button_Click(object sender, RoutedEventArgs e)
{
var result = new StringBuilder(1000);
for(int i = 0; i < 10; i++)
{
//we are creating a new instance
//every single iteration
//this means all these instances
//have the same 'seed'
var rand = new Random();
result.AppendLine(rand.Next().ToString());
}
//produces a lot of duplicates
MessageBox.Show(result.ToString());
}
OUTPUT:
1467722682
1467722682
1467722682
1467722682
1467722682
1467722682
1467722682
1467722682
1467722682
1467722682
The code above produces a lot of duplicates!
A lot of the instances have the same "seed".
Now let's test the claims made in some of the other answers about "fixing" the problem by using a "lock" statement:
private void Button_Click(object sender, RoutedEventArgs e)
{
var result = new StringBuilder(1000);
for(int i = 0; i < 10; i++)
{
//we are creating a new instance
//every single iteration
//this means all these instances
//have the same 'seed'
//now using a lock
lock(this)
{
var rand = new Random();
result.AppendLine(rand.Next().ToString());
}
}
//produces a lot of duplicates
//locking did NOTHING to fix the problem.
MessageBox.Show(result.ToString());
}
OUTPUT:
2013405475
2013405475
2013405475
2013405475
2013405475
2013405475
2013405475
2013405475
2013405475
2013405475
As you can see locking did nothing to solve the problem!
Now let's see how the problem is actually solved:
private void Button_Click(object sender, RoutedEventArgs e)
{
var result = new StringBuilder(1000);
//we are creating a new instance
//outside of the for loop
var rand = new Random();
for(int i = 0; i < 10; i++)
{
result.AppendLine(rand.Next().ToString());
}
//no duplicates
//the problem is now fixed
MessageBox.Show(result.ToString());
}
OUTPUT:
855346142
1488935613
141810032
1396703820
703238132
978249590
138102129
2143944359
224694938
1542730216
As you can see now we have no duplicates.
The actual problem is that the Random class uses the system's clock to create a seed and you create multiple instances very fast they all have the same seed.
Let's look at the documentation of the Random class:
The default seed value is derived from the system clock, which has finite resolution
That is exactly the problem but let's see from the same documentation what Microsoft says about it:
Random objects that are created in close succession by a call to the parameterless constructor will have identical default seed values and, therefore, will produce identical sets of random numbers
Yes that is the exact description of what is happening...
So what does Microsoft say about how to solve this problem:
This problem can be avoided by using a single Random object to generate all random numbers
That is exactly what we did when we moved the instantiation outside of the for loop.
One last note about this:
Note that this limitation does not apply to .NET Core.
Well according to Microsoft this problem no longer happens if you use .NET Core.
It only affects the .NET Framework!
UPDATE:
According to @Aristos the code would behave differently if it were contained withing a classic ASP.NET application.
I just tried the exact same examples in a ASP.NET Application and got the exact same results.
As I expected this issue has nothing to do with ASP.NET.