C# 理解类和使用随机变量
我编写了以下类来返回一个随机数,比如掷骰子:C# 理解类和使用随机变量,c#,class,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; }
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);
}
}
在我的表格中,这个类被调用了好几次:
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();
}
如您所见,我两次调用该类,分别为myRoll
和mySecondRoll
。我认为这样做会创建单独的类实例,并输出两个单独的数字(一个介于1和6之间,另一个介于1和12之间)
我遇到的问题是:
1) 输出的第一个数字始终为0
2) 该类的两个实例相互干扰,即应该在1和6之间的数字不是
我想知道的不仅仅是如何修复代码,还想解释一下这里发生了什么以及为什么会发生这种情况,谢谢。问题是您将Dice类中的字段声明为
static
。这意味着该变量只有一个实例,将在应用程序中的所有类实例之间共享
以下一行:
public int rolled = diceRoll.Next(_minNum, _maxNum);
。。。在您创建新骰子()
时运行,这意味着您尚未初始化\u minNum
和\u maxNum
值:这就是为什么它会给您一个0
。您可以将其转换为属性,因此代码将等待运行,直到您请求:
public int Rolled { get { return diceRoll.Next(_minNum, _maxNum); } }
。。。但通常情况下,不希望仅仅通过询问其价值来改变属性。这类代码倾向于创建所谓的,很难跟踪的代码,因为系统的行为只是通过尝试观察它而改变
因此,这里有一种方法可以重新编写类,使用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();
}
(请注意,“骰子”是“骰子”的单数形式)。用法:
我会将您的类更改为更像以下内容:
class Dice
{
// These are non-static fields. They are unique to each implementation of the
// class. (i.e. Each time you create a 'Dice', these will be "created" as well.
private int _minNum, _maxNum;
// Readonly means that we can't set _diceRand anywhere but the constructor.
// This way, we don't accidently mess with it later in the code.
// Per comment's suggestion, leave this as static... that way only one
// implementation is used and you get more random results. This means that
// each implementation of the Dice will use the same _diceRand
private static readonly Random _diceRand = new Random();
// A constructor allows you to set the intial values.
// You would do this to FORCE the code to set it, instead
// of relying on the programmer to remember to set the values
// later.
public Dice(int min, int max)
{
_minNum = min;
_maxNum = max;
}
// Properties
public Int32 MinNum
{
get { return _minNum; }
set { _minNum = value; }
}
public Int32 MaxNum
{
get { return _maxNum; }
set { _maxNum = value; }
}
// Methods
// I would make your 'rolled' look more like a method instead of a public
// a variable. If you have it as a variable, then each time you call it, you
// do NOT get the next random value. It only initializes to that... so it would
// never change. Using a method will have it assign a new value each time.
public int NextRoll()
{
return _diceRand.Next(_minNum, _maxNum);
}
}
您的get/setter支持字段标记为“
static
”。如果变量声明为“static
”,则该值将在整个应用程序中保持不变,并在其所在类型的不同实例之间共享
看
而且
由于类属性不包含逻辑,我建议使用“automatic
”属性
class Dice
{
public int publicMinNum { get; set; }
public int publicMaxNum { get; set; }
Random diceRoll = new Random();
public int rolled = diceRoll.Next(publicMinNum , publicMaxNum );
}
自动属性教程
您的问题是由于静态
成员造成的
从上的MSDN文档中,“虽然类的实例包含该类所有实例字段的单独副本,但每个静态字段只有一个副本。”问题二已经提出:因为变量是静态的:
static int _minNum;
static int _maxNum;
另一方面,第一个问题尚未得到回答,因此:
public int rolled = diceRoll.Next(_minNum, _maxNum);
这不是什么动态调用。这是一个字段初始化,甚至会在构造函数之前设置。您可以通过第一次调试骰子来检查这一点
此时\u minNum
和\u maxNum
仍为0,因此rolled将设置为0
这也可以通过将Roll转化为属性来解决:
public int rolled
{
get { return diceRoll.Next(_minNum, _maxNum); }
}
目前,\u minNum
和\u 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;
}
}
}
注意,骰子有两个属性: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();
}
我认为这里真正的问题是你没有很好地为模具建模 模具有一个最小值和最大值(定义范围的开始和结束),但一旦模具制作完成,您就无法更改此值,即六面模具不能制作成八面模具。因此,不需要公共设定者 现在,不是所有的骰子都共享相同的范围,这是每个骰子特有的,因此这些属性应该属于实例,而不是 同样,每个模具对象都有一个表示正面朝上的数字的
CurrentRoll
值,这确实是随机生成的。但是,要更改模具的CurrentRoll
,您需要Roll
这使得Die的实现看起来像
class Die
{
private static Random _random;
public int CurrentRoll { get; private set; }
public int Min { get; private set; }
public int Max { get; private set; }
public Die(int min, int max)
{
Min = min;
Max = max;
Roll();
}
public int Roll()
{
CurrentRoll = _random.Next(Min, Max+1); // note the upperbound is exlusive hence +1
return CurrentRoll;
}
}
你会像这样使用它
public static void Main()
{
Die d1 = new Die(1, 6);
Die d2 = new Die(1, 6);
Console.WriteLine(d1.Roll());
Console.WriteLine(d2.Roll());
//...
}
询问教程(或其他广泛的问题)没有建设性,不符合Stack Exchange站点的问答格式,并导致讨论。此代码存在几个问题。整数min和max字段不应是静态的,滚动字段既不应是公共的,也不应按原样初始化。但最重要的是,你需要一个更好的教程,这是正确的,但不幸的是,这不是本网站的主题。我投票认为这不是建设性的。将标题改为更能描述实际问题会有所帮助。他不仅要求提供教程,还存在一些编码问题。所以,没必要投否决票。谢谢。我有一种感觉,可能是因为某种原因,VS非常希望这些变量是静态的,否则它就会爆炸。我猜有一个更好的方法来构建它来解决这个问题?@Chris你是从静态方法还是类来调用它?@Chris:定义“爆炸”。很可能是因为您试图从静态上下文访问其中一个字段。好的,无论是谁通过并对每个答案投了反对票,都需要解释自己。每个答案都是错误的。当您删除static时,请尝试运行*代码。您的输出是否在范围内?不应该这样。请注意这里的第一条评论。“它是炸弹
public static void Main()
{
Die d1 = new Die(1, 6);
Die d2 = new Die(1, 6);
Console.WriteLine(d1.Roll());
Console.WriteLine(d2.Roll());
//...
}