Использование Random.Next () в инициализаторе коллекции / объекта - PullRequest
3 голосов
/ 29 февраля 2012

Может кто-нибудь объяснить, почему приведенный ниже код при запуске иногда приводит к некоторому «NULL!» строки, записываемые в консольное окно?

(Это вопрос TL; DR , читайте дальше)

Это происходит не каждый раз, и вам может понадобиться запустить этот код несколько раз, но достаточно скоро вы увидите строку "NULL!" выводится в окно консоли вместо числа.

По сути, он инициализирует (используя синтаксис сокращенной инициализации коллекции) универсальную коллекцию пользовательских типов (List<Thing>), которая содержит одно свойство, которое является ссылкой на другой пользовательский тип (Numb). Numb предопределено в собственной коллекции (nnn), и объекты из этой коллекции создаются с использованием сокращенного синтаксиса инициализатора объекта из в инициализаторе коллекции с использованием лямбды для выбора случайного объекта на основании единственного num свойства.

nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault() никогда не должен возвращать объект NULL (т.е. часть по умолчанию FirstOrDefault()), так как случайное число должно когда-либо выбирать только 1 или 2, оба из которых существуют в коллекции nnn .

Мои подозрения говорят мне, что это как-то связано с использованием вызова (в частности, множественных вызовов) к rnd.Next() в сценарии инициализатора объекта / коллекции.

Код (запускается как консольное приложение):

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rnd = new Random();

            var nnn = new List<Numb> {
                new Numb() {
                    num = 1
                },
                new Numb() {
                    num = 2
                }
            };

            new List<Thing> {
                new Thing() {
                    numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()
                },
                new Thing() {
                    numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()
                },
                new Thing() {
                    numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()
                },
                new Thing() {
                    numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()
                }
            }.ForEach(t => Console.WriteLine(t.numb!=null ? t.numb.num.ToString() : "NULL!"));

            Console.ReadLine();
        }
    }

    public class Thing
    {
        public Numb numb { get; set; }
    }

    public class Numb
    {
        public int num {get; set; }
    }
}

Ответы [ 3 ]

6 голосов
/ 29 февраля 2012

Вы генерируете другое случайное число для каждого теста предиката . Итак, просто глядя на одну часть:

new Thing() {
    numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()
}

Это будет:

  • Начните итерацию, получите первое Numb - назовем это n1
  • Генерация случайного числа 1 или 2 - назовем это x
  • Проверьте, есть ли n1.num == x, и выдайте его, если так
  • Предполагая, что предыдущий шаг не не соответствует, он будет ...
    • Продолжайте итерацию, получая второе Number - назовем это n2
    • Генерация другого случайного числа, 1 или 2 - назовем это y
    • Проверьте, есть ли n2.num == y, и выдайте его, если так
    • Если предыдущий шаг не не совпадет, он вернет ноль

Другими словами, вы запрашиваете у движущейся цели. Вы хотите сгенерировать одно случайное число, а затем проверить его для всех значений. (Затем повторите для каждого члена инициализатора коллекции.)

2 голосов
/ 29 февраля 2012
 numb = nnn.Where(n => n.num==rnd.Next(1,3)).FirstOrDefault()

Когда rnd генерирует подпоследовательность 2, 1,, вы будете пытаться сопоставить 1 == 2 и 2 == 1 и, следовательно, не найдете совпадения.

0 голосов
/ 29 февраля 2012

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

Таким образом, первый выбирается с вероятностью 1/2, второй с вероятностью 1/4, и ни один с вероятностью 1 / 4.

...