簡體   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