简体   繁体   中英

Why does this code produce the same output for both method calls?

Why does this code produce the same output for both method calls? I would have assumed that because one method is a normal public method and is called from an instance then it would generate a different random number to the static method call as the instance is seperate from the one created for the static method call?

class ClassWithStaticMembers
{

    public static int ReturnAnIntStatic()
    {
        Random random = new Random();
        return random.Next();
    }

    public int ReturnAnInt()
    {
        Random random = new Random();
        return random.Next();
    }
}

class Program
{

    static void Main(string[] args)
    {

        ClassWithStaticMembers classWithStaticMembers = new ClassWithStaticMembers();

        //We can do this because the method is declared static. 
        Console.WriteLine(ClassWithStaticMembers.ReturnAnIntStatic());

        //This can be used as we have not declared this method static
        Console.WriteLine(classWithStaticMembers.ReturnAnInt());

        Console.ReadKey();

}

}

Output is as follows:

12055544 12055544

Can someone explain why using a method call from an instance of a class procuces the same result as a method call from a static method? Are the instances generated for the method calls not different?

EDIT: Further to this. Is the instance of ClassWithStaticMembers used to call the public method seperate to the static call. By which I mean would the compiler use the same instance again if it recognises I am making a call to the same class later in the file?

That's because the Random is by default seeded by the current ticks and since both methods are called at almost the same time, they will produce the same numbers. This is explained in the documentation :

The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor. For more information, see the Random(Int32) constructor.

Put a sleep between the 2 method calls to observe the difference:

Console.WriteLine(ClassWithStaticMembers.ReturnAnIntStatic());
Thread.Sleep(2000);
Console.WriteLine(classWithStaticMembers.ReturnAnInt());

Or use a different constructor for the Random class to seed them differently. Or simply use the same static instance of a Random class:

class ClassWithStaticMembers
{
    private static Random random = new Random();

    public static int ReturnAnIntStatic()
    {
        return random.Next();
    }

    public int ReturnAnInt()
    {
        return random.Next();
    }
}

class Program
{

    static void Main()
    {
        var classWithStaticMembers = new ClassWithStaticMembers();
        Console.WriteLine(ClassWithStaticMembers.ReturnAnIntStatic());
        Console.WriteLine(classWithStaticMembers.ReturnAnInt());
        Console.ReadKey();
    }
}

That's the reason why you should never use the Random class when you require real randomness and not pseudo random numbers. For example in cryptography you should use the RNGCryptoServiceProvider instead of the Random class. Once you know the initial seed value that was used to instantiate the Random class, you can predict all the numbers this class is going to generate.

A guess: It is probably because of the use of the Random Number Generator. Often times, if you initialize a Generator (in any language), it uses the current time as a seed. In your case, this happens at about the same time, so the Generator will return the same number.

In other words: what happens if you do a Console.WriteLine() instead? (or rather return a const int)

EDIT: happens AT the same time, not about, the number of ticks is the same.

This has nothing to do with the distinction between static and instance members.

You're instantiating a Random instance inside each method, and because the methods are called in quick succession both Random instances will use the same seed and therefore produce the same output.

You could use a simpler example to demonstrate that the static and instance methods are distinct:

class ClassWithStaticMembers
{
    public static int ReturnAnIntStatic()
    {
        return 123;
    }

    public int ReturnAnInt()
    {
        return 42;
    }
}

Because in both cases you're using an instance of the Random class; which, due to the fact that they will both be instantiated at very very similar times, produce the same output.

If you use your original code, but introduce a wait between the 2 method calls, it produces different numbers, as per this live example: http://rextester.com/UNH72532

The correct way to use the Random class is to have 1 static instance of it

class ClassWithStaticMembers
{
    private static Random rnd = new Random();
    public static int ReturnAnIntStatic()
    {
        return rnd.Next();
    }
    public int ReturnAnInt()
    {
        return rnd.Next();
    }
}

Both these methods will now produce a random number, check this live example based on your code: http://rextester.com/NBND87340

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM