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

时间:2012-02-23 16:23:35

标签: 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();

}

}

输出如下:

12055544 12055544

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

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

4 个答案:

答案 0 :(得分:9)

这是因为默认情况下Random被当前的刻度线播种,并且由于两种方法几乎同时被调用,因此它们将产生相同的数字。这在documentation

中有解释
  

默认种子值是从系统时钟派生的,并且是有限的   解析度。结果,创建了不同的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类的初始种子值,就可以预测该类将生成的所有数字。

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:4)

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

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

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

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

    public int ReturnAnInt()
    {
        return 42;
    }
}

答案 3 :(得分:3)

因为在这两种情况下你都使用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