For loop never satisfies a condition [duplicate] - c#

This question already has answers here:
Static vs non-static class members
(7 answers)
Closed 4 years ago.
In the current page (which is contained inside a frame inside MainWindow) I have this happen when I click a button:
for (int i = 0; i < mw.pizzas.Length + 1; i++)
{
if (i == 10)
{
MessageBoxResult result = MessageBox.Show("You can't order more than 10 pizzas");
break;
}
if (mw.pizzas[i] == null)
{
mw.pizzas[i] = pizza;
break;
}
}
NavigationService.Content = new AnotherPage();
The mw.pizzas string array contains 10 (I think undefined) variables. I have defined it in MainWindow:
public string[] pizzas = new string[10];
I have defined it on the current page, like so:
MainWindow mw = new MainWindow();
This loop increments by defining these 10 slots with the contents of the variable "pizza". When all of the indexes of the array are defined, a message should pop up. However, this message never shows up. What am I doing wrong here?
Edit: This is just a wild guess. It might have to do with me creating a new CurrentPage every time this page is navigated to. Every time one of these indexes is defined, this navigates back to the previous page, then uses NavigationService.Content = new CurrentPage();
Edit 2: Looks like there is something wrong with the second statement. mw.pizzas[0] is null, then gets the contents of pizza in it, then somehow goes back to being null after the program exits the page and enters it once again.
Edit 3: I tried to make the pizzaIDs array static, but I get the following error: Member 'MainWindow.pizzaIDs' cannot be accessed with an instance reference; qualify it with a type name instead

You loop goes from 0 to 9 inclusive, the array indicies, when it hits 10, it breaks out of the loop and doesn't execute.

Related

How to step into Linq.FindAll query to determine cause of failure using a breakpoint [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 months ago.
I want to use the FindAll method in C# in like this:
List<Card> cards = new List<Card>();
cards.AddRange(testCaseCards);
Console.WriteLine(cards.Count);
List<List<Card>> cardsSuits = new List<List<Card>>();
List<Card> tempList = new List<Card>();
for (int i = 0; i < 4; ++i)
{
Console.WriteLine(cards[i].Suit);
tempList = cards.FindAll(card => card.Suit == (Suit)i);
cardsSuits.Add(tempList);
}
When I initialize my code with testCaseCards containing 9 cards, everything works just fine up until the FindAll query. The value of cards.Count is 9 and cards[i].Suit returns the respective suits.
But when FindAll executes it throws an exception that "card was null" and I'm looking for a way to step into the FindAll as it goes through the cards and set a breakpoint to examine values and determine the exact cause of failure. I looked at this answer which mentions Linq in passing but doesn't provide any real guidance about debugging a null exception while the Linq query is running.
Also, if you notice any other problems in my code please point them out.
One way to debug the FindAll (or any Linq) is by creating a Predicate method. For example:
private static bool isSuit(Card card, Suit suit)
{
if (card == null)
{
// Set a break point here. When the null card comes in
// (as it surely will) you can answer 'why' for yourself.
System.Diagnostics.Debug.Assert(false, "Expecting a non-null card");
return false; // But at least it won't crash now.
}
else
{
return card.Suit == suit;
}
}
Now you will be able to step into this method by changing your FindAll statement to call the predicate instead:
tempList = cards.FindAll(card => isSuit(card, suit));
In addition there is another potential problem. You have a loop where i could mean anything.
for (int i = 0; i < 4; ++i)
In fact the first two statements in the loop interpret it in very different ways. The first statement in the loop seems to think that i is the index in the cards collection. You say cards holds 9 cards. Why stop the loop after 4 then?
Console.WriteLine(cards[i].Suit);
On the other hand, the second line tries to cast i to Suit (which has only four values). if i does go past 4, this won't be good. I would strongly encourage you to change your loop to something like this where we know for sure which collection is being iterated:
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
Console.Write(suit.ToString());
tempList = cards.FindAll(card => isSuit(card, suit));
cardsSuits.Add(tempList);
Console.WriteLine($" has {tempList.Count} cards.");
}
The test case I ran gets this:

Why These two c# scripts give different results? [duplicate]

This question already has answers here:
Regarding local variable passing in Thread
(2 answers)
Closed 2 years ago.
I'm working on a big list of buttons and trying to AddListener() for every Button on this list using a quick way
the first way is
btn[0] = CHbutt[0].GetComponent<Button>(); btn[0].onClick.AddListener(delegate { CH(0); });
btn[1] = CHbutt[1].GetComponent<Button>(); btn[1].onClick.AddListener(delegate { CH(1); });
btn[2] = CHbutt[2].GetComponent<Button>(); btn[2].onClick.AddListener(delegate { CH(2); });
btn[3] = CHbutt[3].GetComponent<Button>(); btn[3].onClick.AddListener(delegate { CH(3); });
and it works very well, and AddListener() to all Buttons in btn[];
but a lot of lines...
the second way
for (int i = 0; i < CHmatt.Count; i++)
{
btn[i] = CHbutt[i].GetComponent<Button>(); btn[i].onClick.AddListener(delegate { CH(i); });
}
but this one is not working, this one AddListener() to only the last button btn[0]
I'm very curious about the difference between these two scripts.
It's a capturing issue. Change the code as follows, to avoid capturing i:
for (int i = 0; i < CHmatt.Count; i++)
{
var ii = i;
btn[i] = CHbutt[i].GetComponent<Button>();
btn[i].onClick.AddListener(delegate { CH(ii); });
}
What is being passed into AddListener function is a delegate method; however, since you're passing in a loop iteration variable i, the context is captured, and i is actually referenced. As your loop advances, the value of i changes for all captures, therefore making this approach "not work".
By introducing a local copy of i (the name is not material here, I called it ii), which goes out of scope on each loop iteration, the capture of i is avoided, and the actual value of ii is passed to the delegate method (technically, captured, but it's a copy of i for each loop iteration, and therefore does not change as i changes.)

Access the value of a variable outside its scope [duplicate]

This question already has answers here:
Access variable inside while loop from outside (C#)?
(4 answers)
Closed 2 years ago.
I am new to C# and trying to automate a window app using appium .I have the following code
int i = -1;
foreach (var row in SummaryTableRows)
{
i++;
//Console.WriteLine(row.Text);
if ((row.Text.Contains("cheq")) && (row.Text.Contains("acitve")))
{
var DemandData = FirstRow.Split(new[] { " " },
StringSplitOptions.RemoveEmptyEntries);
string Sub = DemandData[1];
string Type = DemandData[0];
bFlag = true;
break;
}
}
buttonBar.ExitFormBtn.Click();
buttonBar = null;
//Should be back to member form
SubCheq.SendKeys(Sub + Keys.Tab);
I want to access the value of Sub and Type outside the if loop. In vb script it was never an issue but seems like in C# the scope of the variable is limited to the foreach block. So My question how can I access the value of Sub and Type.
You can not access a variable outside of it's scope. The scope literally means "where you can access the variable". So you want to accesss the values, where you can not access the values. At wich point you can access the variable there, and that is it's new scope.
What you can do is change the scope. If you want a variable avalible outside a specific block, declare it outside of that block. Just declare sub (and propably type) outside the loop. Then only set the values insdie it, with every loop.
I am unsure why you even ask, as you already do that with i: int i = -1; is a declaration with initialisation. And i++; is jsut shorthad for i=i+1;, so you re-assing it every loop (the new value just happens to be close to the ol one). Strings you many want to initialize with null or maybe a empty string, depending on what you do with it later/how you check for 0 itterations of the foreach loop.

Index out of range using lists and for loop

I have this loop here, which for each question it is supposed to create, it generates and then formats a 'worded question' from an array of questions, such as; 'What is the sum of {0} + {1}?'. This loop then formats it, adds the worded question and the answer to an array.
// Use for loop to create the correct amount of questions
for (int i = 0; i < Data.Questions.numQuestions; i++)
{
Random rnd = new Random();
Data.Questions.Sum sum = new Data.Questions.Sum();
// Create part one and part two of the question using random numbers
// ex. 3 + 5
// 3 = partOne, 5 = partTwo
int partOne = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
int partTwo = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
// Randomly select one of the word questions
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
// Format the string with the generated numbers
fullQuestion = string.Format(fullQuestion, partOne, partTwo);
// Set out-of-class variables to be displayed to the user
Data.Questions.Sum.questions[i] = fullQuestion;
Data.Questions.Sum.answers[i] = partOne + partTwo;
}
Both Data.Questions.Sum.questions and Data.Questions.Sum.answers are List<string>'s and List<int>'s.
However, when this loop is run, with i = 0, I am thrown;
System.ArgumentOutOfRangeException: 'Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index'
Does anyone know what I'm doing wrong? As far as I know lists are dynamic, and I've defined like this;
// Arrays containing all questions and answers
// used to display questions and check answers
public static List<string> questions = new List<string>();
public static List<int> answers = new List<int>();
Also, to clarify, I do not want to use .Add(), as I have a settings panel which when you hit apply, re-runs this loop so the questions are up to date to the current settings. I need the loop to override the previous values.
Edit:
When using arrays, the better option here, I get;
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
On assigning Data.Questions.Sum.answers[i], after assigning the array like so; public static int[] answers {};
If you can't .Add() in this lists - create a copy of this lists and .Add() there. Lists has special for that kind of thing: new List<T>(IEnumerable<T>)
If you need to dynamically scale the collection, but you also need to iterate over it multiple times, then you'll need to check whether it is large enough to either insert, or just update.
You can do this with an extension method such as this...
public static class ListExtentions
{
public static void AddOrUpdate<T>(this List<T> that, int index, T value)
{
if (that.Count > index)
{
that[index] = value;
}
else
{
that.Add(value);
}
}
}
...which can then be called like this...
list.AddOrUpdate(index, value);
...however you can make things easier for yourself if you know how many questions you are going to have to start with.
If the number of questions changes when your UI changes, then you will also have to deal with the issue have scaling down the collection to ensure old elements are removed, which is much simpler if you just re-instantiate the collections every time you need to regenerate the questions / answers.
This is likly to be cause of your problem,(I have asked for clarification in comments where you didn't reply).
Still putting this as an answer, as it is potential error spot and you need to fix this.
As you mentioned you are facing this exception on i=0. there are high chanced that this is every time case not any specific case.
If Data.Questions.Sum.questions is empty then, Data.Questions.Sum.questions[i] = fullQuestion; , will surely throw such exception. Same way for Data.Questions.Sum.answers too.
In such case, you must use .Add() to insert into list.
so your code should be,
if (Data.Questions.Sum.questions.Count > i)
Data.Questions.Sum.questions[i] = fullQuestion;
else
Data.Questions.Sum.questions.Add(fullQuestion);
But if they are not empty, it must not be the cause of this exception.
One more thing i have noticed in your code is Data.Questions.Sum.wordedQuestions.
Even if you have valid list (here Data.Questions.Sum.wordedQuestions) - as you have Length prop, it must be Array not list.
If it is empty, while doing this
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
this line will surely throw
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
as you are trying to get 0th index's data from it.
So before fetching data from list or array, first you need to check if it does have data init, and also it does have that index which you are asking.
something like
string fullQuestion = string.Empty;
if (Data.Questions.Sum.wordedQuestions != null &&
Data.Questions.Sum.wordedQuestions.Length > 0)
{
//here the way you are creating random number,
// you are assured about index is present in array.
int indexForWordedQuestion = rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length);
fullQuestion = Data.Questions.Sum.wordedQuestions[indexForWordedQuestion];
}

C# modifying a list in a function [duplicate]

This question already has answers here:
Directly modifying List<T> elements
(6 answers)
Closed 8 years ago.
I am writing a function which is passed in a list which is partially filled. I'd like to set some of the fields within the list inside this function. I thought that passing it as a reference would allow me to do this, however, I get the following error:
Error 1 Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable
I am wondering what I might need to do to tell C# that I wish to have the option of modifying the contents of the list.
Here is a summarized version of my code:
public static void Determine_RTMM_Descriptor(ref List<Struct_Descriptor_Type> symbols, string Dwarf_Output_Filename)
{
...
lines = System.IO.File.ReadAllLines(Dwarf_Output_Filename);
//loop on symbol names
for (int idx = 0; idx < symbols.Count; idx++)
{
if(symbols[idx].size == 0)
symbols[idx].size = (int)new System.ComponentModel.Int32Converter().ConvertFromString(split_line[DwarfInterface.SIZE_INDEX]);
...
}
Thanks in advance for any help.
The underlying issue here is that you have a list of value types. When you use the indexer of the list to get an item from the list you are getting a copy of that type. The code symbols[idx] is the value of that item. It is not a variable representing that item, as the error message is telling you.
You're trying to mutate the size of the copy, which will have no effect on the item of the list. This is such a common mistake that the compiler even makes this an error.
If you really are sure that you want to have a mutable value type (hint: you aren't, and you shouldn't have one; you almost certainly just want to have a class here to avoid this problem entirely) then you would need to get the value of the item, mutate it, and then set the item again:
if(symbols[idx].size == 0)
{
var symbol = symbols[idx];
symbol.size = 42;
symbols[idx] = symbol;
}
Your return type on the function is "void" when you should set the return type to the list. That should allow you to change it and return it modified.

Categories