繁体   English   中英

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

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

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

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

}

}

输出如下:

12055544 12055544

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

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

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

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

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

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

或者使用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();
    }
}

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

猜测:可能是因为使用了随机数生成器。 通常,如果初始化Generator(使用任何语言),它会将当前时间用作种子。 在您的情况下,这几乎在同一时间发生,因此Generator将返回相同的数字。

换句话说:如果你做一个Console.WriteLine()会发生什么? (或者更确切地说,返回一个const int)

编辑:同时发生,而不是,蜱的数量是相同的。

这与静态成员和实例成员之间的区别无关。

您在每个方法中实例化一个Random实例,并且因为这些方法是快速连续调用的,所以Random实例将使用相同的种子,因此产生相同的输出。

您可以使用更简单的示例来演示静态和实例方法是不同的:

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

    public int ReturnAnInt()
    {
        return 42;
    }
}

因为在这两种情况下你都使用Random类的实例 ; 由于它们将在非常相似的时间实例化,因此产生相同的输出。

如果您使用原始代码,但在两个方法调用之间引入等待,则会产生不同的数字,如本实例所示: http//rextester.com/UNH72532

使用Random类的正确方法是拥有1个静态实例

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

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

暂无
暂无

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

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