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;
}
Related
I'm currently taking a intermediate course on Udemy for C# and I'm trying to do one of the exercises. I've looked in the Q&A for students to see other peoples solutions, I've even copied and pasted other peoples solutions to see if theirs works and they do, I don't see any difference between mine and other peoples but for some reason my code prints out the numbers from highest to lowest and no where in the code should this happen. The idea of the exercise was to create a stack, we have 3 methods: Push(), Pop(), and Clear(). The push method adds objects to an ArrayList, the pop method removes the number from the top of the stack and returns the number. The clear method is self explanatory. Here's my code:
Stack Class:
public class Stack {
private ArrayList _arrayList = new ArrayList();
public void Push(object obj) {
if (obj is null) {
throw new InvalidOperationException();
}
else {
_arrayList.Add(obj);
}
}
public object Pop() {
if (_arrayList is null) {
throw new InvalidOperationException();
}
else {
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
}
}
public void Clear() {
for (int i = 0; i < _arrayList.Count; i++) {
_arrayList.Remove(i);
}
}
}
Program Class:
class Program {
static void Main(string[] args) {
var stack = new Stack();
stack.Push(5);
stack.Push(1);
stack.Push(2);
stack.Push(4);
stack.Push(3);
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
}
}
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
You aren't printing the values, you're printing the number of elements stored.
Try changing your values to be something other than the first few positive integers to catch this kind of mistake more easily.
PS: There's been no reason to use ArrayList for over a decade. The generic collection classes such as List<int> are better in every way -- faster, less wasted memory, type safety.
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
top is assigned the value of the size of the list, and is never reassigned. Thus it looks like it prints highest to lowest because its just printing the size of the stack (which of course is 5, then 4, then 3, and so on). It only looks like you printed the contents of your list because you happened to push the same numbers. Some different test data would have made this bug more obvious.
I think what you actually wanted was
var top = _arrayList[_arrayList.Count -1];
Note that your code would fail miserably if there was a duplicate element in the list (due to removing based on the item value and not on the index). You also really shouldn't be using ArrayList at all; that's a .NET 1.0 class that's just an awful collection interface. Use a generic like List<T>.
You are returning
var top = _arrayList.Count;
Not the value in that position.
_arrayList(top-1);
You should be getting an index out of range error on that remove.
_arrayList.Remove(top);
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 ();
I am new to programming in C# and I'm having problems generating random numbers from input read form a file. I am trying to generate random numbers from the second field on each line from the following input read from a text file
4321,99
5432,79
6543,59
7654,39
The file is read by the following code, then parsed into separate fields where a method is called to generate a random number
private void readFileButton_Click(object sender, EventArgs e)
{
string readString;
inputFile = File.OpenText(sourceFileString);
while (!inputFile.EndOfStream)
{
readString = inputFile.ReadLine();
var flds = readString.Split(',');
string patID = flds[0];
int months = Convert.ToInt32(flds[1]);
Random();
}
inputFile.Close();
}
The method I am using that generates a random number from the second field
private void Random()
{
Random rand2Integer = new Random();
randomInteger = rand2Integer.Next(1, months) + 1;
}
However, this exception is thrown: 'minValue' cannot be greater than maxValue, and I can't wrap my head around it. If I manually enter the data on a form using a text box then the random number is generated as expected. Any input to guide me along?
From your code it looks like you have a class variable months. However, while reading file you have declared a local variable which essentially hides the class variable.
Now when you use Random function, the class variable is used (which must have 0 and causing this error)
replace the following line of code
int months = Convert.ToInt32(flds[1]);
with
months = Convert.ToInt32(flds[1]);
The variable months in Random() is not the same that the one you are assigning in int months = Convert.ToInt32(flds[1]); the last is local to the method.
You should define month outside or pass it as a parameter to Random()
EDIT:
I made minor changes to make code easier to read. Hope it helps.
private void readFileButton_Click(object sender, EventArgs e)
{
// If you use the stream this way it will be disposed automatically.
using (var sr = new StreamReader(sourceFileString))
{
while (!sr.EndOfStream)
{
string readString = sr.ReadLine();
var flds = readString.Split(',');
string patID = flds[0];
int months = int.Parse(flds[1]);
//I prefer parameters more than fields to communicate between methods.
Random(months);
}
}
}
Random randomGenerator = new Random();
private void Random(int months)
{
randomInteger = randomGenerator.Next(1, months) + 1;
}
In the readFile function, you declare a variable called months and initialize it to the number from your file. This appears correct and probably works great.
However, that variable has function scope. You likely have another variable called "months" at the class level (otherwise you would be getting a compile time error). This variable, and not the one set in "readFile", is what is used by the "Random" method. Change the line to:
months = Convert.ToInt32(flds[1]);
and it will work.
As an aside, you should not use a new instance of Random every time you need a draw. It is considered better practice to have one instance per object and reuse it each time you need a new random number.
for the life of me, I cannot figure this out. Basically I am trying to make a search function with an unsorted list of objects. No matter what I try, the location returns -1. When I look at the logic, it makes sense to me, but maybe I've been staring at my screen for too long. Any help would be greatly appreciated!
public static int ContactSearchFirst(List<Contact> contactList, string userInput)
{
int location = -1;
for (int index = 0; index < contactList.Count && location == -1; index++)
{
if (contactList[index].FirstName.ToUpper().Equals(userInput.ToUpper()))
{
location = index;
}
}
return location;
}
If you're using C#, then the whole loop is un-necessary. You can simply use the List<T>.FindIndex method:
public static int ContactSearchFirst(List<Contact> contactList,
string userInput)
{
return contactList
.FindIndex(c =>
c.FirstName.Equals(userInput,
StringComparison.InvariantCultureIgnoreCase));
}
You may also want to trim the input so that leading/trailing spaces don't cause unexpected results.
You would only get a new location value if the following is ever true, so maybe it never is true:
if (contactList[index].FirstName.ToUpper().Equals(userInput.ToUpper()))
Perhaps the parameters are being passed incorrectly when the function is called.
If you are using visual studio you can easily check this by setting a break point in your code and inspecting the contactList and userInput variables.
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;
}
}