【问题标题】:Halt until object created successfully [closed]暂停直到成功创建对象[关闭]
【发布时间】:2015-02-08 19:45:16
【问题描述】:

我是一名初级程序员,需要一些帮助。在我的程序开始时,创建了 5 个兔子(对象类型 Bunny)。它看起来像这样:

List<Bunny> bunnies = new List<Bunny>();
Bunny newBunny;
for(int i = 0; i < 5; i++)
{
    newBunny = new Bunny();
    bunnies.Add(newBunny);
 }

我的问题是 newBunny 的构建耗时太长,程序继续使用 for 循环。这会导致列表只有第一个构造的 newBunny 和它的副本。运行代码会打印出以下内容:

姓名 - 凯特,性别 - 男,颜色 - 白色,年龄 - 0,放射性 - 假

姓名 - 凯特,性别 - 男,颜色 - 白色,年龄 - 0,放射性 - 假

姓名 - 凯特,性别 - 男,颜色 - 白色,年龄 - 0,放射性 - 假

姓名 - 凯特,性别 - 男,颜色 - 白色,年龄 - 0,放射性 - 假

姓名 - 凯特,性别 - 男,颜色 - 白色,年龄 - 0,放射性 - 假

结构如下:

public Bunny()
{
     Random randNum = new Random ();
     int namesCount = Enum.GetNames(typeof(BunnyName)).Length;
     Name=((BunnyName)(randNum. Next(0, namesCount)));

     int genderCount = Enum.GetNames(typeof(BunnyGender)).Length;
     Gender=((BunnyGender)(randNum. Next(0, genderCount)));

     int colorCount = Enum.GetNames(typeof(BunnyColor)).Length;
     Color=((BunnyColor)(randNum. Next(0, colorCount)));

     Age=-1;

     if(randNum. Next(1,101)<2)
         Radioactive = true;
     else
         Radioactive =false;
} 

我希望程序停止直到 newBunny 的构建结束,然后才将其添加到列表中:

List<Bunny> bunnies = new List<Bunny>();
Bunny newBunny;
for(int i = 0; i < 5; i++)
{
    //stop until next line finishes
    newBunny = new Bunny();
    //continue
    bunnies.Add(newBunny);
 }

附言。如果我正在调试程序,它运行得很好,就像我想要的一样(新兔子不是“重复”) 此外,如果我在 for 循环的末尾添加一个 messageBox,一切正常。 这就是为什么我认为它可能需要暂停

for(int i = 0; i < 5; i++)
{
    //stop until next line finishes
    newBunny = new Bunny();
    //continue
    bunnies.Add(newBunny);
    MessageBox.Show("test");
 }

希望您能理解我的问题,谢谢。

【问题讨论】:

  • “我的问题是 newBunny 的构建耗时太长,程序继续 for 循环。这导致列表中只有第一个构建的 newBunny 和它的副本。”不,那不是真的。目前尚不清楚您为什么认为会发生这种情况,但事实并非如此。请提供一个简短但完整的程序来演示该问题,我们可以帮助您诊断它。另请注意,通过在循环而不是外部声明变量inside,您的代码会更好(IMO) - 通常,对局部变量使用尽可能小的范围。
  • 你怎么确定它是同一个对象?
  • 如果使用在构造函数内部启动的非阻塞线程(用于初始化对象的属性),可能会导致此行为,但鉴于您是新程序员,您不太可能这样做这个。
  • 你所有的Randoms 都有相同的种子。
  • 这样做:静态随机 randNum = new Random ();您的程序实际上非常快。 Random 使用相同的基于时间的种子,并始终生成相同的数字,通过将其设为静态,只会创建一个 Random 实例并一直重复使用,从而生成新的随机数,而不是始终生成相同的随机数。

标签: c#


【解决方案1】:

Random in a loop?它们可能是不同的对象,但你所有的随机数都是一样的。

这是因为Random 的构造函数在没有参数的情况下使用来自系统时钟的种子。因此,如果您像这样快速更新它们,它们最终都会相同,并且在您调用 Next 时会给出相同的值。

最好将一个 Random 传递给所有构造函数并使用它。

List<Bunny> bunnies = new List<Bunny>();
Random random = new Random();
for(int i = 0; i < 5; i++)
{
    bunnies.Add(new Bunny(random));
}

您也不需要变量来将兔子保持在不必要的高位scope。如果你只在 for 循环中使用某些东西,它不需要存在于它之外。

有人建议在 Bunny 类中使​​用静态 Random,但我不建议这样做。将东西注入实例有很多好处(尤其是在多线程时),但在您的情况下,优势是可测试性。

我在下面包含了一个类作为示例,您可以使用它来测试您的 Bunny 构造函数,您可以控制生成的兔子,然后验证发生的事情是否正确:

class MyRandomIsAlwaysN : Random
 {
    private readonly int nextValue;

    public MyRandomIsAlwaysN(int n){
        this.nextValue = n;
    }
    public override int Next(int x, int y){
         return this.nextValue
    }
 }

【讨论】:

    【解决方案2】:

    您遇到的问题在于您对 Random 的使用。

    请看这里:C# Random Numbers aren't being "random"

    我建议你在 bunny 之外创建一个 Random 类,然后将其传递给构造函数。

    List<Bunny> bunnies = new List<Bunny>();
    Bunny newBunny;
    Random randomGenerator = new Random();
    for(int i = 0; i < 5; i++)
    {
        newBunny = new Bunny(randomGenerator);
        bunnies.Add(newBunny);
    }
    

    【讨论】:

      【解决方案3】:

      您的程序执行是完全同步的,所以实际上列表中有 5 个不同的 Bunny 实例。 如果您不相信我,请更改 Bunny 的构造函数并为其添加一个整数。在构造函数中,将此整数分配给 Bunny 的实例变量,如下所示:

      public class Bunny{
          private int _instanceId;
      
          public Bunny(int instanceId){
              _instanceId = instanceId;
          }
      }
      

      在循环中这样做:

      newBunny = new Bunny(i);
      

      现在使用调试器单步调试代码。希望视觉工作室。在 add 语句上放置一个断点并将光标导航/悬停在 bunnies 变量上以查看里面的内容。你甚至可以检查不同的实例,你会发现 instanceid 是不同的。 您的代码只创建了 5 个不同的 Bunny 实例,但由于构造函数相同,您最终会得到 5 个看起来完全相同的实例。

      要获得真正随机的值,请在构造函数中执行此操作:

      static Random randNum = new Random ();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-15
        • 1970-01-01
        • 2017-10-27
        • 1970-01-01
        • 1970-01-01
        • 2012-08-21
        • 2016-06-19
        • 1970-01-01
        相关资源
        最近更新 更多