Почему этот код выдает одинаковые выходные данные для обоих вызовов метода? - PullRequest
2 голосов
/ 23 февраля 2012

Почему этот код выдает одинаковый вывод для обоих вызовов метода? Я бы предположил, что, поскольку один метод является обычным общедоступным методом и вызывается из экземпляра, он генерирует другое случайное число для вызова статического метода, поскольку экземпляр отделен от того, который создан для вызова статического метода?

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 ]

9 голосов
/ 23 февраля 2012

Это потому, что по умолчанию Random засвечивается текущими тиками, и поскольку оба метода вызываются практически одновременно, они будут выдавать одинаковые числа. Это объясняется в документации :

Начальное значение по умолчанию получено из системных часов и имеет конечное значение. разрешающая способность. В результате различные случайные объекты, которые создаются в Закрыть последовательность путем вызова конструктора по умолчанию будет иметь идентичные начальные значения по умолчанию и, следовательно, будут выдавать наборы случайных чисел. Этой проблемы можно избежать, используя один Случайный объект для генерации всех случайных чисел. Вы также можете обойти это путем изменения начального значения, возвращаемого системными часами, а затем явное предоставление этого нового начального значения для Random (Int32) конструктор. Для получения дополнительной информации см. Конструктор Random (Int32).

Поставьте режим ожидания между вызовами двух методов, чтобы увидеть разницу:

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, вы можете предсказать все числа, которые сгенерирует этот класс.

4 голосов
/ 23 февраля 2012

Это не имеет ничего общего с различием между статическими и экземплярами-членами.

Вы создаете экземпляр Random внутри каждого метода, и потому что методы вызываются в быстрой последовательности как Random экземпляровбудет использовать то же начальное число и, следовательно, производить тот же вывод.

Можно использовать более простой пример, чтобы продемонстрировать, что методы static и instance различны:

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

    public int ReturnAnInt()
    {
        return 42;
    }
}
4 голосов
/ 23 февраля 2012

Предположение: возможно, из-за использования генератора случайных чисел. Часто, если вы инициализируете Генератор (на любом языке), он использует текущее время в качестве начального числа. В вашем случае это происходит примерно в одно и то же время, поэтому Генератор вернет тот же номер.

Другими словами: что произойдет, если вместо этого вы сделаете Console.WriteLine ()? (вернее, возвращает const int)

РЕДАКТИРОВАТЬ: происходит в то же время, не примерно, число тиков одинаково.

3 голосов
/ 23 февраля 2012

Потому что в обоих случаях вы используете экземпляр класса Random; которые из-за того факта, что они оба будут созданы в очень и очень похожие времена, производят один и тот же результат.

Если вы используете свой исходный код, но вводите ожидание между вызовами двух методов, он генерирует разные числа, как показано в следующем примере: http://rextester.com/UNH72532

Правильный способ использования класса Random - иметь один статический экземпляр этого класса

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...