Halt until object created successfully [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
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.

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

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

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

Related

Logic errors get solved upon converting object to string

Sorry if this has been answered before, but I haven't gotten any relevant results by looking up the title, and I'm not sure how else to phrase this.
I've been learning C# recently. Three times now, I've experienced a logic error that was fixed via converting an object to a string.
The first time, I was generating a random number. When I didn't convert it, I generated the same number repeatedly. When I did, the RNG worked as expected. The problem was from initializing the random variable inside the loop, instead of outside.
The second and third times involves me trying to get the first item in a list via indexing. Whenever I don't use .ToString(), the object returns null. When I do convert the item, I get the correct value. What makes it especially weird is what happens when using the debugger. When I place the breakpoint before .ToString(), the value returns null, even if I run the .ToString() line afterwards. When I place the breakpoint at or after .ToString(), the value displays just fine. In addition, I've been using a bound listbox to help me debug, and the bound listbox displays the items in the list perfectly. I still don't know what's causing these problems.
I'd like to know why this is happening. These problems are really annoying, and I'd like to avoid them in the future. If .ToString() is fixing them, then that means there's something that .ToString() does that fixes it, and I'd like to know how & why.
Sorry if any of my phrasing is wonky -- I've never been a good writer.
Update: Sorry, I didn't add the code because I wasn't sure if it was relevant or not. Here are some recreations of the error
For the RNG error:
private int GenerateNumber()
{
Random random = new Random();
int returnInt = random.Next(1, 6);
return returnInt;
}
private void DisplayResult()
{
listBox1.BeginUpdate();
int[] displayArray = new int[5];
foreach (int i in displayArray)
{
int temp = GenerateNumber();
listBox1.Items.Add(temp);
}
listBox1.EndUpdate();
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
DisplayResult();
// displays the same number
}
The .ToString() "fix" is the same code, except for the foreach loop in DisplayResult(), which is changed to:
foreach (int i in displayArray)
{
int temp = GenerateNumber();
MessageBox.Show(temp.ToString());
listBox1.Items.Add(temp);
}
I can't write up the other two right now, but I will ASAP.
Don't make a Random object inside the method. Change:
private int GenerateNumber()
{
Random random = new Random();
int returnInt = random.Next(1, 6);
return returnInt;
}
to:
Random random = new Random();
private int GenerateNumber()
{
int returnInt = random.Next(1, 6);
return returnInt;
}

C# Winforms: Why does 'i' output as 2 both times [duplicate]

I'm using Task to process multiple requests in parallel and passing a different parameter to each task but it seems all the tasks takes one final parameter and execute the method using that.
Below is the sample code. I was expecting output as:
0 1 2 3 4 5 6 ..99
but I get:
100 100 100 ..10 .
May be before print method is called, i's value is already 100 but shouldn't each method print the parameter passed to it? Why would print method takes the final value of i?
class Program
{
static void Main(string[] args)
{
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
t[i] = Task.Factory.StartNew(() => print(i));
}
Task.WaitAll(t);
Console.WriteLine("complete");
Console.ReadLine();
}
private static void print(object i)
{
Console.WriteLine((int)i);
}
}
You're a victim of a closure. A simplest fix to this issue is:
for (int i = 0; i < 100; i++)
{
int v = i;
t[i] = Task.Factory.StartNew(() => print(v));
}
You can find more detailed explanations here and here.
Problems occur when you reference a variable without considering
its scope.
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
t[i] = Task.Factory.StartNew(() => print(i));
}
Task.WaitAll(t);
You might think that, your task will consider each i th value in it's execution. But that won't happen since Task execution start sometime in future. That means, the variable i is shared by all the closures created by the steps of the for loop. By the time the tasks start, the value of the single, shared variable i. This is why all task print same ith value.
The solution is to introduce an additional temporary variable in
the appropriate scope.
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
var temp=i;
t[i] = Task.Factory.StartNew(() => print(temp));
}
Task.WaitAll(t);
This version prints the numbers 1, 2, 3, 4..100 in an arbitrary order, but each
number will be printed. The reason is that the variable tmp is declared
within the block scope of the for loop’s body. This causes a new
variable named tmp to be instantiated with each iteration of the for
loop. (In contrast, all iterations of the for loop share a single instance
of the variable i.)
For info, another fix here is to use the state parameter of the Task API, i.e.
t[i] = Task.Factory.StartNew(state => print((int)state), i);
Unfortunately, since the state parameter is object, this still boxes the value, but it avoids needing an entire closure and separate delegate per call (with the code shown immediately above, the compiler is smart enough to use a single delegate instance for all the iterations; this is not possible if you add a local variable (like the v in BartoszKP's answer), as the target is the closure instance, and that then varies per iteration).

Why would Task object not use parameter passed to it?

I'm using Task to process multiple requests in parallel and passing a different parameter to each task but it seems all the tasks takes one final parameter and execute the method using that.
Below is the sample code. I was expecting output as:
0 1 2 3 4 5 6 ..99
but I get:
100 100 100 ..10 .
May be before print method is called, i's value is already 100 but shouldn't each method print the parameter passed to it? Why would print method takes the final value of i?
class Program
{
static void Main(string[] args)
{
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
t[i] = Task.Factory.StartNew(() => print(i));
}
Task.WaitAll(t);
Console.WriteLine("complete");
Console.ReadLine();
}
private static void print(object i)
{
Console.WriteLine((int)i);
}
}
You're a victim of a closure. A simplest fix to this issue is:
for (int i = 0; i < 100; i++)
{
int v = i;
t[i] = Task.Factory.StartNew(() => print(v));
}
You can find more detailed explanations here and here.
Problems occur when you reference a variable without considering
its scope.
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
t[i] = Task.Factory.StartNew(() => print(i));
}
Task.WaitAll(t);
You might think that, your task will consider each i th value in it's execution. But that won't happen since Task execution start sometime in future. That means, the variable i is shared by all the closures created by the steps of the for loop. By the time the tasks start, the value of the single, shared variable i. This is why all task print same ith value.
The solution is to introduce an additional temporary variable in
the appropriate scope.
Task[]t = new Task[100];
for (int i = 0; i < 100; i++)
{
var temp=i;
t[i] = Task.Factory.StartNew(() => print(temp));
}
Task.WaitAll(t);
This version prints the numbers 1, 2, 3, 4..100 in an arbitrary order, but each
number will be printed. The reason is that the variable tmp is declared
within the block scope of the for loop’s body. This causes a new
variable named tmp to be instantiated with each iteration of the for
loop. (In contrast, all iterations of the for loop share a single instance
of the variable i.)
For info, another fix here is to use the state parameter of the Task API, i.e.
t[i] = Task.Factory.StartNew(state => print((int)state), i);
Unfortunately, since the state parameter is object, this still boxes the value, but it avoids needing an entire closure and separate delegate per call (with the code shown immediately above, the compiler is smart enough to use a single delegate instance for all the iterations; this is not possible if you add a local variable (like the v in BartoszKP's answer), as the target is the closure instance, and that then varies per iteration).

Array of Monitors in C#

I'm currently trying to implement the Dining Philosopher problem, however I'm running into an issue. I declare my forks as such
public static fixed Monitor forks[5];
however when I try to reference them via
forks[i].Enter();
I'm only given the possibility of "Equals, GetType, ToString, GetHashCode."
Does anyone know how to create an array of Monitors and lock each specific Monitor?
You just need to create an array of objects - you can't create an instance of Monitor; it's a static class. (I'm surprised you can even declare the array - although it's not clear why you've decided to use fixed sized buffers, either. Stick with safe code, I suggest.)
So:
object[] forks = new object[5];
for (int i = 0; i < forks.Length; i++)
{
forks[i] = new object();
}
Then you can use:
Monitor.Enter(forks[x]);
to acquire the monitor for the index x.
In C#, you can lock on any object, methods on Monitor are static.
So your code should be done this way:
List<object> locks = new List<object>();
for (int i = 0; i < 5; i++) locks.Add(new object());
// ...
Monitor.Enter(locks[0]);

Random Number Generation - Same Number returned [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
c# - getting the same random number repeatedly
Random number generator not working the way I had planned (C#)
I have a method that builds a queue of ints:
public Queue<int> generateTrainingInts(int count = 60)
{
Queue<int> retval = new Queue<int>();
for (int i = 0; i < count; i++)
{
retval.Enqueue(JE_Rand.rInt(2001, 100));
}
return retval;
}
JE_Rand.rInt() is just a function that delegates to a function of the Random class:
public static int rInt(int exclUB, int incLB = 0)
{
Random rand = new Random(DateTime.Now.Millisecond);
int t = rand.Next(incLB, exclUB);
rand = null;
return t;
}
But when I call generateTrainingInts, the same number is enqueued each time. However, if I change rInt to use a static instance of the Random class, instead of a local instance (with function scope as it is defined above), then it appears to work correctly (enqueue random integers). Does anybody know why this happens?
Edit:
Dear Answerers who didn't read my question thoroughly,
Like some of you pointed out, I am looking for a good explanation of why this happens. I am not looking for a solution to the same-number-generated problem, because I already fixed that like I said above. Thanks for your enthusiasm though :) I really just want to understand things like this, because my first implementation made more sense conceptually to me.
You need to keep the same Random object. Put it outside your static method as a static member
private static Random rand = new Random();
public static int rInt(int exclUB, int incLB = 0)
{
int t = rand.Next(incLB, exclUB);
return t;
}
Edit
The reason is the finite resolution of the clock used to initialize Random. Subsequent initializations of Random will get the same starting position in the random sequence. When reusing the same Random the next value in the random sequence is always generated.
Try out the following code and I think you'll see why:
void PrintNowAHundredTimes()
{
for (int i = 0; i < 100; ++i)
{
Console.WriteLine(DateTime.Now);
}
}
The Random objects are getting the same seed over and over. This is because the granularity of the system time returned by DateTime.Now is, quite simply, finite. On my machine for example the value only changes every ~15 ms. So consecutive calls within that time period return the same time.
And as I suspect you already know, two Random objects initialized with the same seed value will generate identical random sequences. (That's why it's called pseudorandom, technically.)
You should also be aware that even if it made sense to instantiate a new Random object locally within your method, setting it to null would still serve no purpose (once the method exits there will be no more references to the object anyway, so it will be garbage collected regardless).
public class JE_Rand
{
private static Random rand= new Random(DateTime.Now.Millisecond);
public static int rInt(int exclUB, int incLB = 0)
{
int t = rand.Next(incLB, exclUB);
return t;
}
}

Categories