理解类并使用Random

Chr*_*ris -1 c# class

我写了下面的类来返回一个随机数,比如掷骰子:

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

namespace GameTest
{
    class Dice
    {
    public int publicMinNum
    {
        get { return _minNum; }
        set { _minNum = value; }
    }

    public int publicMaxNum
    {
        get { return _maxNum; }
        set { _maxNum = value; }
    }

    static int _minNum;
    static int _maxNum;

    static Random diceRoll = new Random();
    public int rolled = diceRoll.Next(_minNum, _maxNum);
 }
}
Run Code Online (Sandbox Code Playgroud)

这个类在我的表单中被称为几次:

    private void btnPushMe_Click(object sender, EventArgs e)
    {
        Dice myRoll = new Dice();
        myRoll.publicMinNum = 1;
        myRoll.publicMaxNum = 7;

        lblMain.Text = myRoll.rolled.ToString();

        Dice mySecondRoll = new Dice();
        mySecondRoll.publicMinNum = 1;
        mySecondRoll.publicMaxNum = 13;

        lblMain2.Text = mySecondRoll.rolled.ToString();
    }
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我调用类的两倍myRoll和mySecondRoll.我想通过这样做它会创建类的单独实例并输出两个单独的数字(一个在1和6之间,另一个在1和12之间)

我遇到的问题是:

1)第一个数字输出总是0.

2)该类的两个实例相互干扰,即.应该在1到6之间的数字不是.

我想知道,不仅仅是如何修复代码,还想要解释这里发生了什么以及为什么,谢谢.

Str*_*ior 5

问题是您将Dice类中的字段声明为static.这意味着该变量只有一个实例,它将在应用程序中的所有类实例之间共享.

以下行:

public int rolled = diceRoll.Next(_minNum, _maxNum);
Run Code Online (Sandbox Code Playgroud)

...获取运行您创建的那一刻new Dice(),这意味着你还没有初始化,您_minNum和_maxNum价值观尚未:这就是为什么它给你一个0.您可以将其转换为属性,因此代码会等待您运行,直到您要求它为止:

public int Rolled { get { return diceRoll.Next(_minNum, _maxNum); } }
Run Code Online (Sandbox Code Playgroud)

......但通常不会通过询问属性来改变属性.这种代码往往会产生所谓的Heisenbugs,它很难追踪,因为系统的行为只是通过试图观察而改变.

所以这里有一种方法可以重新编写你的类,使用一种Roll()方法来实际执行roll,以及一个允许代码在必要时继续检查最后一个roll值的属性:

public class Die
{

    // Using a constructor makes it obvious that you expect this
    // class to be initialized with both minimum and maximum values.
    public Die(int minNum, int maxNum)
    {
        // You may want to add error-checking here, to throw an exception
        // in the event that minNum and maxNum values are incorrect.

        // Initialize the values.
        MinNum = minNum;
        MaxNum = maxNum;

        // Dice never start out with "no" value, right?
        Roll();
    }

    // These will presumably only be set by the constructor, but people can
    // check to see what the min and max are at any time.
    public int MinNum { get; private set; }

    public int MaxNum { get; private set; }

    // Keeps track of the most recent roll value.
    private int _lastRoll;

    // Creates a new _lastRoll value, and returns it.
    public int Roll() { 
        _lastRoll = diceRoll.Next(MinNum, MaxNum);
        return _lastRoll;
    }

    // Returns the result of the last roll, without rolling again.
    public int LastRoll {get {return _lastRoll;}}

    // This Random object will be reused by all instances, which helps
    // make results of multiple dice somewhat less random.
    private static readonly Random diceRoll = new Random();
}
Run Code Online (Sandbox Code Playgroud)

(注意"死"是"骰子"的单数形式).用法:

private void btnPushMe_Click(object sender, EventArgs e)
{
    Die myRoll = new Die(1, 7);
    lblMain.Text = myRoll.Roll().ToString();

    Die myRoll2 = new Die(1, 13);
    lblMain2.Text = mySecondRoll.Roll().ToString();
}
Run Code Online (Sandbox Code Playgroud)


Ron*_*ijm 5

问题二已经解决了:因为变量是静态的:

static int _minNum;
static int _maxNum;
Run Code Online (Sandbox Code Playgroud)

另一方面问题一还没有回答,所以这里有:

public int rolled = diceRoll.Next(_minNum, _maxNum);
Run Code Online (Sandbox Code Playgroud)

这不是一些动态的电话.这是一个字段初始化,甚至会在构造函数之前设置.您可以通过第一次通过骰子调试来检查这一点.

在这一点上两者_minNum并_maxNum仍然为0,所以推出将被设置为0

这可以通过将滚动转换为属性来修复:

    public int rolled
    {
        get { return diceRoll.Next(_minNum, _maxNum); }
    }
Run Code Online (Sandbox Code Playgroud)

目前_minNum并且_maxNum第一次设置因为它们是静态的,因此当你创建第二个骰子时,它们已经被设置.

编辑,因为提出了建议,这就是我创建它的方式:

骰子

class Dice
{
    private static Random diceRoll = new Random();

    private int _min;
    private int _max;
    public int Rolled { get; private set; }

    public Dice(int min, int max)
    {
        _min = min;
        _max = max;

        // initializes the dice
        Rolled = diceRoll.Next(_min, _max);
    }

    public int ReRoll
    {
        get
        {
            Rolled = diceRoll.Next(_min, _max);
            return Rolled;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,骰子有两个属性:Rolled和ReRoll.因为你的意图不清楚,我已经加上两个来说明行为.

Rolled由构造函数设置.如果你想要一个新号码,你可以ReRoll.

如果你故意想要一个掷骰的寿命是每个骰子一个(但我不这么认为)你将删除该ReRoll方法.

骰子会像这样调用:

    private static void Main(string[] args)
    {
        Dice myRoll = new Dice(1, 7);

        // All the same
        var result1 = myRoll.Rolled.ToString();
        var result2 = myRoll.Rolled.ToString();
        var result3 = myRoll.Rolled.ToString();

        // something new
        var result4 = myRoll.ReRoll.ToString();

        Dice mySecondRoll = new Dice(1, 13);
        var result = mySecondRoll.ReRoll.ToString();
    }
Run Code Online (Sandbox Code Playgroud)