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

CSh*_*ned 2 c# static

为什么这个代码为两个方法调用产生相同的输出?我会假设因为一个方法是一个普通的公共方法并且从一个实例调用然后它会为静态方法调用生成一个不同的随机数,因为该实例与为静态方法调用创建的实例是分开的?

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();

}
Run Code Online (Sandbox Code Playgroud)

}

输出如下:

12055544 12055544

有人可以解释为什么使用来自类实例的方法调用会产生与静态方法中的方法调用相同的结果吗?为方法调用生成的实例是否没有区别?

编辑:继续这一点.ClassWithStaticMembers的实例是否用于将公共方法调用为静态调用.我的意思是如果编译器识别出我稍后在文件中调用同一个类,那么编译器会再次使用相同的实例吗?

Dar*_*rov 9

这是因为默认情况下Random是由当前的ticks播种的,因为两种方法几乎同时被调用,所以它们将生成相同的数字.这在文档中解释:

默认种子值源自系统时钟并具有有限的分辨率.因此,通过调用默认构造函数紧密连续创建的不同Random对象将具有相同的默认种子值,因此将生成相同的随机数集.使用单个Random对象生成所有随机数可以避免此问题.您还可以通过修改系统时钟返回的种子值,然后将此新种子值显式提供给Random(Int32)构造函数来解决此问题.有关更多信息,请参阅Random(Int32)构造函数.

在2个方法调用之间进行休眠以观察差异:

Console.WriteLine(ClassWithStaticMembers.ReturnAnIntStatic());
Thread.Sleep(2000);
Console.WriteLine(classWithStaticMembers.ReturnAnInt());
Run Code Online (Sandbox Code Playgroud)

或者使用Random类的不同构造函数以不同方式对它们进行种子设定.或者只是使用类的相同静态实例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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么当你需要真正的随机性而不是伪随机数时你永远不应该使用Random类的原因.例如,在加密中,您应该使用RNGCryptoServiceProvider而不是Random类.一旦知道用于实例化Random类的初始种子值,就可以预测该类将生成的所有数字.