简体   繁体   English

为什么这个代码为两个方法调用产生相同的输出?

[英]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 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. ClassWithStaticMembers的实例是否用于将公共方法调用为静态调用。 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. 这是因为默认情况下Random是由当前的ticks播种的,因为两种方法几乎同时被调用,它们将产生相同的数字。 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. 因此,通过调用默认构造函数紧密连续创建的不同Random对象将具有相同的默认种子值,因此将生成相同的随机数集。 This problem can be avoided by using a single Random object to generate all random numbers. 使用单个Random对象生成所有随机数可以避免此问题。 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. 您还可以通过修改系统时钟返回的种子值,然后将此新种子值显式提供给Random(Int32)构造函数来解决此问题。 For more information, see the Random(Int32) constructor. 有关更多信息,请参阅Random(Int32)构造函数。

Put a sleep between the 2 method calls to observe the difference: 在2个方法调用之间进行休眠以观察差异:

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

Or use a different constructor for the Random class to seed them differently. 或者使用Random类的不同构造函数以不同方式对它们进行种子设定。 Or simply use the same static instance of a Random class: 或者只是使用Random类的相同静态实例:

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. 这就是为什么当你需要真正的随机性而不是伪随机数时你永远不应该使用Random类的原因。 For example in cryptography you should use the RNGCryptoServiceProvider instead of the Random class. 例如,在加密中,您应该使用RNGCryptoServiceProvider而不是Random类。 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. 一旦知道用于实例化Random类的初始种子值,就可以预测该类将生成的所有数字。

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. 通常,如果初始化Generator(使用任何语言),它会将当前时间用作种子。 In your case, this happens at about the same time, so the Generator will return the same number. 在您的情况下,这几乎在同一时间发生,因此Generator将返回相同的数字。

In other words: what happens if you do a Console.WriteLine() instead? 换句话说:如果你做一个Console.WriteLine()会发生什么? (or rather return a const int) (或者更确切地说,返回一个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. 您在每个方法中实例化一个Random实例,并且因为这些方法是快速连续调用的,所以Random实例将使用相同的种子,因此产生相同的输出。

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; 因为在这两种情况下你都使用Random类的实例 ; 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 如果您使用原始代码,但在两个方法调用之间引入等待,则会产生不同的数字,如本实例所示: http//rextester.com/UNH72532

The correct way to use the Random class is to have 1 static instance of it 使用Random类的正确方法是拥有1个静态实例

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 这两种方法现在都会生成一个随机数,请根据您的代码查看此实例: http//rextester.com/NBND87340

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么完全相同的代码产生不同的结果? - Why does the exact same code produce different results? 为什么这个 azure function 会产生 JSON Z78E6221F6393D1356681DBCE39? - Why does this azure function produce a JSON output? 为什么此代码会产生“非静态字段,方法或属性需要对象引用”的编译错误? - Why does this code produce an 'An object reference is required for the non-static field, method, or property' compilation error? 为什么这个非常简单的C#方法会产生这种不合逻辑的CIL代码? - Why does this very simple C# method produce such illogical CIL code? 为什么 C# 编译器不会在静态方法调用实例方法的地方出现错误代码? - Why does the C# compiler not fault code where a static method calls an instance method? 为什么相同的代码大小会产生不同大小的exe文件 - why is the same code size produce different size exe file 为什么此 C# 方法无法生成正确的屏幕截图? - Why does this C# method not produce the right screenshot? 为什么C#的Replace方法需要在我的代码中同时替换“ \\ n”和“ \\ r”? - Why does C#'s Replace method need to replace both “\n” and “\r” in my code? 为什么代码会产生ObjectDisposedException - Why the code produce ObjectDisposedException 为什么以下代码会产生对象处置异常 - Why does the following code produce Object Disposed Exception
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM