来自“Head Start C# Greyhound Lab”的 C# newb 问题

本文关键字:newb 问题 Lab Greyhound Head Start 来自 | 更新日期: 2023-09-27 18:02:21

我是 C# 的新手,我正在创建一个赛道模拟器,但我目前在运行代码时遇到了一些问题。我有一个包含四个灰狗对象的数组,如果我在我的 form1 上调用 Greyhound.Run.cs并且我的 Run 方法上没有"MessageBox.Show("距离"+ 距离(",它显示了每只灰狗应该移动多少像素,那么所有灰狗最终都会移动相同的距离。我不明白为什么会这样

namespace Race
{
    class Greyhound
    {
        public int StartingPosition;
        public int RacetrackLength;
        public PictureBox MyPictureBox = null;
        public int Location = 0;
        public Random Randomizer;
        public bool Run()
        {
            Point p = MyPictureBox.Location;
            if (p.X + MyPictureBox.Width >= RacetrackLength)
            {
                //TakeStartingPostion();
                return true;
            }
            else
            {
                Randomizer = new Random();
                int distance = Randomizer.Next(100);
                MessageBox.Show("Distance is " + distance);
                p.X += distance;
                MyPictureBox.Location = p;
                return false;
            }
        }
        public void TakeStartingPostion()
        {
            Point P = MyPictureBox.Location;
            P.X = StartingPosition;
            MyPictureBox.Location = P;
        }
    }
}

namespace Race
{
    public partial class Form1 : Form
    {
        Guy[] guys = new Guy[3];
        Greyhound[] hounds = new Greyhound[4];
        public Form1()
        {
            InitializeComponent();
            hounds[0] = new Greyhound()
            { 
                StartingPosition = 12,
                MyPictureBox = GreyHound1,
                RacetrackLength = 636
            };
            hounds[1] = new Greyhound()
            { 
                StartingPosition = 12,
                MyPictureBox = GreyHound2,
                RacetrackLength = 636
            };
            hounds[2] = new Greyhound()
            { 
                StartingPosition = 12,
                MyPictureBox = GreyHound3,
                RacetrackLength = 636
            };
            hounds[3] = new Greyhound()
            { 
                StartingPosition = 12,
                MyPictureBox = GreyHound4,
                RacetrackLength = 636
            };
        }
        private void button2_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < hounds.Length; i++)
            {
                 hounds[i].Run();
            } 
        }
    }
}

来自“Head Start C# Greyhound Lab”的 C# newb 问题

这是因为每次Run()方法命中else块时都会调用new Random()。默认Random构造函数根据当前时间初始化伪随机数生成器。当没有中断时,所有 4 个方法都在"同一时间"运行,因此它们吐出相同的随机数。要解决此问题,请仅创建一个Random,或者为每个种子使用不同的种子(通过使用将种子作为参数的Random构造函数(。

这样的东西会起作用:

public class Greyhound
{
    public static Random randomizer = new Random();
    // ... In the run method ...
    int distance = Greyhound.randomizer.Next(100);
}

更新:正如Groo指出的那样,如果您实际上从多个线程调用Next(),那么我显示的代码不是线程安全的。虽然您的代码并非如此,但最好尽早了解此类问题。这个(潜在(问题的一般解决方案是用lock包围对Next()的调用,如下所示:

// ... After the declaration of randomizer ...
private static object randomLock = new object();
// ... New Next() call...
lock (randomLock)
    Greyhound.randomizer.Next(100);

由于您可能连续快速地调用所有对象的Run方法,因此 Random 类的每个实例都使用相同的种子实例化,返回相同的伪随机数。

您可以通过创建一个静态随机类来解决此问题,该类将具有单个(单例(Random实例,确保每个调用方连续获得下一个号码。

通过一些线程安全锁定,它看起来像:

 public class StaticRandom 
 {
      private static readonly Random _r = new Random();
      private static object _lock = new object();
      public static int Next(int max)
      {
           lock (_lock)
               return _r.Next(max);
      }
 }

然后在不实例化的情况下使用它:

 // no need for the "Randomizer" field anymore
 int distance = StaticRandom.Next(100);

Jon Skeet在他的miscutil库中有完整的实现,以及一些使用信息。