Pourquoi est le système.Classe aléatoire pas statique?

Lorsque vous utilisez la classe System.Random, vous devez en faire une instance. Pourquoi n'est-ce pas static? Parce que si je veux un nombre aléatoire entre 0 et 9, je peux utiliser la statique méthode, System.Random.Next(int, int):

int ourRandomNumber = Random.Next(0,9);

Alors pourquoi la classe n'est-elle pas juste static?

24
demandé sur Cole Johnson 2011-02-08 16:47:33

5 réponses

Vous ne seriez pas en mesure d'utiliser des graines différentes si elles étaient statiques - l'instance aléatoire garde la trace de cet état. Par défaut, Random utilise L'heure actuelle comme graine, mais la réutilisation d'une graine particulière (c'est-à-dire new Random(42)) vous permet de répéter exactement la séquence de nombres aléatoires - ils seront toujours les mêmes pour la même graine. Cet aspect est très important dans certaines applications. Par exemple, Minecraft.

31
répondu BrokenGlass 2014-03-28 16:13:50

Random n'est pas thread-safe. Il est bon d'avoir une instance de Random par thread, mais vous ne devriez pas utiliser une instance de plusieurs threads simultanément. Vous ne pouvez donc pas avoir une seule instance de Random dans une variable statique et l'utiliser à partir de la méthode statique.

En outre, le rendre statique supprimerait la possibilité de donner une graine spécifique, comme mentionné par BrokenGlass.

Bien sûr, il ne serait pas trop difficile de créer des méthodes statiques qui prennent soin de la sécurité des threads lorsque vous ne le faites pas besoin d' pour spécifier une graine, mais toujours laisser les méthodes d'instance pour lorsque vous souhaitez utiliser une instance particulière. Personnellement, je trouve approprié de traiter "une source de nombres aléatoires" comme une dépendance à injecter le cas échéant.

J'ai un article qui couvre une partie de ce et que vous trouverez peut-être utile.

17
répondu Jon Skeet 2011-02-08 13:51:36

Parfois, vous voulez "quelque chose de Aléatoire", et vous ne vous souciez pas de la façon dont cette valeur aléatoire est arrivée. Avoir une méthode statique pour cela pourrait fonctionner.

Cependant, parfois vous voulez être capable d'obtenir de manière répétée la même séquence aléatoire. Pour cela, vous utilisez la surcharge du constructeur qui prend une valeur de départ, et dans ce cas, vous ne voulez pas qu'un autre code utilisant des nombres aléatoires consomme l'un des nombres de votre séquence. Dans ce cas, vous avez certainement besoin d'un instance de la classe

4
répondu Damien_The_Unbeliever 2011-02-08 13:51:47

Avoir une séquence 'aléatoire' répétable est utile dans les scénarios de test.

Par exemple, vous pouvez l'utiliser pour tester un moteur de jeu pour vous assurer qu'une IA sélectionne correctement des cibles, ou des chemins, même si elle a une évaluation de chemin aléatoire.

Voici un exemple très simpliste. Peu importe combien de fois vous exécutez ce test, il choisira toujours les mêmes trois cartes lorsqu'il est donné le même générateur de nombres aléatoires de base. Cela peut être utile pour s'assurer que le générateur de nombres aléatoires utilisé est celui fourni. Et, pour une raison quelconque, si un nouveau générateur de nombres aléatoires était introduit sans modifier le test, le test échouerait.

[TestMethod]
public void TestRandomPicking()
{
    Random random = new Random(1);
    Deck deck = new Deck(random);


    Assert.AreEqual(3, deck.PickCard().Value);
    Assert.AreEqual(1, deck.PickCard().Value);
    Assert.AreEqual(5, deck.PickCard().Value);

}

public class Deck
{
    public Deck()
    {
        _randomizer = new Random();
    }

    public Deck(Random randomizer)
    {
        _randomizer = randomizer; 
    }

    Random _randomizer;

    private List<Card> _cards = new List<Card>
                                    {
                                        new Card {Value = 1},
                                        new Card {Value = 2},
                                        new Card {Value = 3},
                                        new Card {Value = 4},
                                        new Card {Value = 5},
                                        new Card {Value = 6},
                                        new Card {Value = 7},
                                        new Card {Value = 8},
                                        new Card {Value = 9},
                                        new Card {Value = 10}
                                    };

    private List<Card> Cards { get { return _cards; } }

    public Card PickCard()
    {
        return Cards[_randomizer.Next(0, Cards.Count - 1)];
    }
}

public class Card
{
    public int Value { get; set; }
}
2
répondu 2011-02-08 14:09:07

Souvent, lorsque l'on débogue un programme, un comportement inapproprié à une étape peut ne pas avoir de symptômes visibles jusqu'à ce que de nombreuses autres étapes aient été exécutées, date à laquelle la cause initiale peut avoir été obscurcie. Dans de tels cas, il peut être très utile de pouvoir redémarrer à partir de zéro un programme qui a mal fonctionné sur, par exemple, l'étape 1 000 000 et de le faire exécuter les premières 999 990 étapes exactement comme il l'a fait la première fois, puis faire une pause pour laisser le programmeur examiner son état. Un tel débogage ne sera pas possible si un programme génère des nombres vraiment "aléatoires", mais le sera s'il utilise à la place un générateur pseudo-aléatoire qui peut être rechargé lors de la deuxième exécution avec la même graine que celle utilisée lors de la première exécution.

1
répondu supercat 2013-11-15 19:04:24