.net c#暂停直到成功创建对象

Halt until object created successfully [closed]
2020-11-21
  •  译文(汉语)
  •  原文(英语)

我是一名初学者,需要一些帮助.在我的程序开始时,创建了5个兔子(对象类型为"兔子").看起来像这样:

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

我的问题是newBunny的构建时间太长,并且该程序继续使用for循环.这导致列表只有第一个构造的newBunny及其副本.运行代码将向我显示以下内容:

凯特(Name-Kate),性别男性,色白,0岁,放射性假

凯特(Name-Kate),性别男性,色白,0岁,放射性假

凯特(Name-Kate),性别男性,色白,0岁,放射性假

凯特(Name-Kate),性别男性,色白,0岁,放射性假

凯特(Name-Kate),性别男性,色白,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");
 }

希望您理解我的问题,谢谢.

速聊1:
"我的问题是newBunny的构建花费了太长时间,并且该程序继续使用for循环.这导致列表仅包含第一个构造的newBunny及其副本." 不,那不是真的.目前尚不清楚为什么会这样,但事实并非如此.请提供简短但完整的程序来演示该问题,我们将帮助您进行诊断.还要注意,通过在循环内部而不是外部声明变量,可以使代码更好(IMO)-通常,对局部变量使用尽可能小的范围.
速聊2:
您如何确定它是同一对象?
速聊3:
如果使用在构造函数内部启动的非阻塞线程(用于初始化对象的属性),则可能会导致此行为,但是看到您是新程序员,就不太可能这样做.
速聊4:
您所有Random的人都有相同的种子.
速聊5:
执行以下操作:静态Random randNum = new Random(); 您的程序实际上非常快.Random使用相同的基于时间的种子,并始终生成相同的数字,通过使其为静态,将仅创建一个Random实例并一直重复使用,从而始终生成新的随机数,而不是始终相同.
解决过程1

随机循环吗?它们可能是不同的对象,但是您的所有随机数都相同.

这是因为Random,如果没有提供参数,则for的构造函数将使用系统时钟中的种子.因此,如果您像这样快速地将它们更新,则它们在调用时都会以相同的方式结束并给出相同的值Next.

最好将一个Random传递给所有构造函数,然后改用它.

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

您也不需要变量将兔子保持在不必要的高范围内.如果仅在for循环中使用某些内容,则它不需要在其外部存在.

已经建议在Bunny类中使用静态Random,但是我建议不要这样做.将事物注入实例有很多好处(尤其是在多线程的情况下),但是在您的情况下,好处是可测试性.

我在下面提供了一个类作为示例,您可以使用这些类来测试Bunny构造函数,可以控制制作的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类,然后将其传递给构造函数.

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 ();

I'm a beginner programmer and need some help. In the beginning of my program, 5 bunnies (object type Bunny) are created. It looks like this:

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

My problem is that the construction of newBunny takes too long and the program continues with the for-loop. This causes the list to have just the first constructed newBunny and duplicates of it.Running the code prints me the following:

Name-Kate, Gender-Male, Color-White, Age-0, Radioactive-False

Name-Kate, Gender-Male, Color-White, Age-0, Radioactive-False

Name-Kate, Gender-Male, Color-White, Age-0, Radioactive-False

Name-Kate, Gender-Male, Color-White, Age-0, Radioactive-False

Name-Kate, Gender-Male, Color-White, Age-0, Radioactive-False

The construction looks like this:

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;
} 

I want the program to halt until the construction of newBunny ends, and only then to add it to the list:

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);
 }

Ps. If I'm debugging the program it runs just fine, exactly like i want it to (new bunnies not 'duplicates') Also, if I add a messageBox in the end of the for-loop, everything works good. This is why i thought it might need a halt

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

Hope you understood my problem, thanks.

Talk1:
"My problem is that the construction of newBunny takes too long and the program continues with the for-loop. This causes the list to have just the first constructed newBunny and duplicates of it." No, that's just not true. It's not clear why you think that's happening, but it's not. Please provide a short but complete program demonstrating the problem, and we can help you diagnose it. Also note that your code would be better (IMO) by declaring the variable inside the loop instead of outside - in general, use the smallest possible scope for local variables.
Talk2:
And how did you determine it's the same object?
Talk3:
This behaviour could be caused if using non-blocking threads which are launched inside the constructor (used to initialise your object's properties), but seeing as you're a new programmer it is unlikely that you are doing this.
Talk4:
All of your Randoms have the same seed.
Talk5:
do this : static Random randNum = new Random (); Your program is actually very fast. The Random is using the same time based seed, and generates always the same numbers, by making it static, there will be only one Random instance created and reused all the time generating new random numbers instead of always the same ones.
Solutions1

Random in a loop? They may be different objects but all your random numbers are the same.

This is because the constructor for Random, when given no parameters uses a seed from the system clock. So if you new them up quickly like this they all end up the same and will give the same value when you call Next.

Much better to pass one Random into all of the constructors and use that instead.

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

You also don't need a variable to hold the bunnies at an unnecessarily high scope. If your using something in the for loop only, it doesn't need to exist outside of it.

Having a static Random in the Bunny class has been suggested, but i'd advise against it. There are a lot of benefits of injecting things into the instance (especially when mult-threading), but in your case the advantage is testability.

I've included a class below as an example of something you could use to test your Bunny constructor, you can control the bunny that gets made and then verify that what happened is correct:

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
    }
 }
Solutions2

The problem you have is in your usage of Random.

See here: C# Random Numbers aren't being "random"

I would suggest you create one Random class outside of bunny, and then pass that into the constructor.

i.e

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);
}
Solutions3

Your program execution is totally synchronous so in fact there are 5 different instances of Bunny in the list. If you don't believe me change the constructor of Bunny and add an integer to it. In the constructor assign this integer to an instance variable of Bunny like so:

public class Bunny{
    private int _instanceId;

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

in the loop do this :

newBunny = new Bunny(i);

now use the debugger to step through the code. Hopefully visual studio. Put a break point on the add statement and navigate/hover the cursor over the bunnies variable to see what is inside. You can even inspect the different instances and you will see the instanceid is different. Your code just creates 5 different instances of Bunny, but because the constructor is the same, you end up with 5 instances that look exactly the same.

To get really random values do this in your constructor :

static Random randNum = new Random ();
转载于:https://stackoverflow.com/questions/28398536/halt-until-object-created-successfully

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入