I've come across a minor issue (for this time) which is the following:
When I debug my code in Visual Studio Community 2017 and edit anything while it's inside a foreach, then all variables in that scope, including the variable being iterated, are set to null.
foreach (var bFile in baseCache) {
var file = lastFolder + "\\" + bFile.Value.relPath;
if (!lastCache.ContainsKey(file)) {
if (file.Length > 255) { continue; }
// TODO: do stuff when the file isn't present in the last backup
}
var lFile = lastCache[file];
var comp = bFile.Value.compare(lFile);
if (!comp.HasFlag(FileData.CompareFlags.CRC32 & FileData.CompareFlags.Size)) {
}
}
In this part for example, I had a breakpoint at the 4th line, where it goes if "lastCache" doesn't contain the key that's represented by "file" at that time.
At that time there was just the continue; sitting at that spot and I changed it as it is shown now, and when I pressed F10 to step further because I wanted to verify this issue at that point, all variables shown in the snippet went 'null'.
Can someone explain to me why this is happening and how I can hopefully avoid this?
Currently this is just a minor bother when I'm changing things, but if this happens later in a bigger project it will be a real problem...
Edit: here's a link to the whole code, it's just a console app so luckily, that's easily done
https://www.pastiebin.com/5cf3e7dfa2985
The scope of variables declared in the body of the loop is this very loop body. When you are entering the loop body they are not yet defined. E.g. lFile and comp will not have a value until the assignments have been executed.
If you want to preserve the value over several loops, then declare the variables before the loop.
A note to using dictionaries. it is more efficient to test the presence of a key and to get the value at once with TryGetValue
if (lastCache.TryGetValue(file, out string lFile)) {
// do something with lFile.
} else {
// file is missing
}
Related
I'm building a turn-based battle system and something is puzzling me right now. I've been able to fix the issue, however, I have NO IDEA as to why one way works and the other doesn't.
This is the block of code :
foreach (GameObject wrapper in wrappers) {
Destroy(wrapper);
}
wrappers.Clear();
I should also mention that I'm using unity, which locks me in C#4 (I'm aware they released an experimental support for C#6 but I'm having enough trouble right now, without adding unstable features)
So I have a State Machine for the GUI placed in the Update() function.
switch(heroInputState) {
case HeroGUI.ACTIVATE: {
if(heroesToManage.Count > 0) {
actionPanel.SetActive(true);
choiceMade = false;
currentIndex = 0;
HighlightText(actions[currentIndex]);
spellBook.AddRange(heroesToManage[0].GetComponent<HeroStateMachine>().hero.spellBook);
heroInputState = HeroGUI.SELECT_COMMAND;
}
break;
}
case HeroGUI.SELECT_COMMAND: {
////
//The code works when placed here
////
ChooseAction(actions, actions); //This simply allows me to move the cursor in the actionMenu by highlighting the current index of the "actions" list. When I press the E key, the choice is made.
actionType = CheckAction();
if (choiceMade) {
switch(actionType) {
case "Magic": {
CreateSubMenuRows(); //This is the problem function
break;
}
default: {
heroInputState = HeroGUI.SELECT_TARGET; //The next state in the state machine, not relevant to this question
break;
}
}
}
break;
}
}
private void CreateSubMenuRows() {
int rowCount = 0;
////
//But isn't working here
////
//Instantiate a new prefab holding 3 "namePlate" when the spell name and cost will appear
while(rowCount < Mathf.CeilToInt((float)spellBook.Count / 3)) {
GameObject newHorizontalWrapper = Instantiate(horizontalWrapper, transform.position, Quaternion.identity);
newHorizontalWrapper.transform.SetParent(verticalWrapper.transform, false);
wrappers.Add(newHorizontalWrapper);
rowCount++;
}
SortTextElements(); //This takes all <Text> elements in scene and sort them into two list used to manipulate the color of those elements
numberOfRows = rowCount;
}
So this whole thing works on the first pass, I can select the action, the spell, and process the action. I also clear the List of Text elements in the last state of the machine since it depends on the number of spells in the current heroesToManage's spellBook.
When hero's turn comeback, the list shows 0 element, until I get to the CreateSubMenuRows function once again... In my case, there are 6 spells, meaning that it should have only 6 elements for each SpellName... However, if the block of code is placed at the start of the CreateSubMenuRows function, for some exotic reason, it finds 12 Text elements (6 of which have been destroyed and are now showing as missing), as if the list didn't clear the first time, even if it DOES show 0 element in the inspector until that point, the wrappers have been destroyed and the list of wrappers has been cleared... then I get a MissingReferenceException since it tries to load the destroyed Text element...
After fiddling for quite a while, I tried to move the destroy loop BEFORE the if statement and strangely, everything now works as intended. However, since I want to learn, I need to understand why exactly this thing isn't working when it's after the if statement...
Sorry if it seems a bit messy, I'm still learning how to write clean code. Also, since this thing is 500 lines long, which would be way to many lines to post here, it can seem like a lot is missing but I can assure you that everything related is there
So, working in C#. I have a CSS-based drop-down menu. I open the menu, then grab a reference to it using FindElement by CSSSelector. I then grab the contents of the list using FindElements, again by CSSSelector.
Now here's where it get's interesting. I iterate the list, based on a file I have open in a streamreader.
Looks something like:
list = driver.FindElement(By.CSSSelector("dropdown-menu"));
list_items = list.FindElements(By.CSSSelector("LI > A"));
int row = 0;
while (data_file.read())
{
iWebElement item = list_items[row];
string label = item.text;
string url = item.getattribute("href");
assert.areequal("something", label);
assert.areequal("something else", url);
row++;
}
Now here's the thing: if the mouse pointer is placed over the drop-down, while this is executing, item.text returns value and the test succeeds. If the pointer is anywhere else, item.text will be blank and the test fails. Trying to understand what's going on, and taking a clue from the fact that though the test would fail when running, but would succeed while stepping, I modified the code with a loop:
while (data_file.read())
{
iWebElement item = list_items[row];
string label = item.text;
while (label == "")
{
label = item.text;
}
string url = item.getattribute("href");
assert.areequal("something", label);
assert.areequal("something else", url);
row++;
}
Now the test will always succeed, but if the pointer is not on the control it is SIGNIFICANTLY slower... we're talking a factor of 4 or 5... then when the pointer IS on the control. By wrapping a timer around this, I find that it typically takes between 2 and 4 seconds before .text returns anything but an empty string... sometimes longer.
Again, this delay only seems to apply when the mouse pointer is not over the drop-down. Otherwise, the value appears to be there instantaneously.
Can anyone suggest a possible explanation for why it's behaving this way, and a possible approach to solving it?
BTW, I'm not finding any difference between:
item = list_items[row];
label = item.text;
and
label = list_items[row].text;
Nor does .getattribute("value") produce any faster results than .text.
As for why the menus are acting this way, it's hard to tell with the code you've provided. If you could provide the code that displays your menu, that might help. As for solutions, there are a couple.
The label could be taking longer to display because of the while loop itself - it's just going crazy grabbing the text over and over very quickly. A better solution would be to wait for the element to be present. This may make your code run faster. See the Selenium Website for information on using WebDriverWait.
Alternatively, there is an "ugly" solution. You can just move the mouse to the menu with Selenium, to make sure the menu is always displayed when you need it. I've adapted some code from here as an example:
OpenQA.Selenium.Interactions.Actions builder = new
builder.MoveToElement(list).Build().Perform();
Hope this helps!
So for fun, I decided to write a tool that loads a game's ini file(Outlast) and then lets you change the values for certain things.
The way I did this was, in the original ini, I found the line number the variable was on, and then removed the variable name in the code leaving only the value it held, and it wrote that to the textbox.
I am horrible at explaining things, so to clarify, in this particular ini file this is what line 42 is:
NormalWalkSpeed=200,
And in the code, I did this to write that number to a textbox:
WalkSpeedTxtBox.Text = GameLocation.DefaultGameIniLines[42].Replace("NormalWalkSpeed=", "");
And to change it, this is the button's code:
GameLocation.DefaultGameIniLines[42] = "NormalWalkSpeed=" + walkspeed;
System.IO.File.WriteAllLines(GameLocation.DefaultGameIniLocation, GameLocation.DefaultGameIniLines);
MessageBox.Show("Success! Walk speed has been set to " + WalkSpeedTxtBox.Text);
System.Media.SystemSounds.Beep.Play();
So the problem right off the bat with this is, obviously, if the ini file is not exactly the same as it was before, as in the lines change, this will no longer work and I'd have to rewrite everything.
What exactly would be a better way of doing what I want to do?
INI files are structured configuration files, which allow you to find a value given its Group and Key. Treating it as a sequential collection of lines will miss that point - and treating each line as simply a bunch of text means more work for you.
Assuming you want to write this code yourself rather than using an existing INI reading library, the best thing to do is to run over the INI file, converting it into a Dictionary of Dictionaries. A Dictionary is the data structure that makes most sense, since it allows you to access a collection of Keys by their Group name, and a value by its Key name.
Something like this:
Dictionary<string, Dictionary<string,string>> Groups = new...
string currentGroupName;
foreach (string line in File.ReadAllLines(iniFile))
{
if (lineStartsWith("[") && line.EndsWith("]"))
{
currentGroupName = line.Substring(1, line.Length-2);
Groups.Add(currentGroupName, new Dictionary<string,string>());
}
else if (line.Contains("="))
{
string[] keyValue = line.Split("=");
Groups[currentGroupName].Add(keyValue[0], keyValue[1]);
}
}
This, roughly, will allow you to iterate on all the groups and their keys, getting the values. You can then construct a list of Strings back from it to save.
you could try to find that string in file and if found you can fetch its value
using (var reader = new StreamReader(file))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line.Contains("NormalWalkSpeed="))
{
//get its value
}
}
}
I have a scenario where in a continuously running thread "timer" calls my function "custommethod". I have no control over system code this is just to demonstrate how the system works i am not even aware of what code has been written in system code.
system code
timer duration = 1000
void timer_elapsed()
{
foreach(string symbol in symbols) //symbol list may vary
{
custommethod(symbol);
}
}
end system code
so, my method "custommethod" just gets a parameter from system code periodically. The symbol list may vary when the user adds or removes the symbols which is handled by system code. what all i get is active symbols periodically. so, my concern is to keep a list of active symbols.
my code
function custommethod(string symbol)
{
//Check whether new symbol is added or a symbol is deleted
}
end my code
This is what i have tried so far
HashTable ht=new HashTable();
function custommethod(string symbol)
{
//Check whether new symbol is added or a symbol is deleted
if(!ht.ContainsKey(symbol))
{
ht.Add(symbol,0); //New symbol added
}
//How will i come to know whether a symbol is deleted or not
}
If ht is the same symbols then it's bad. One should never mutate the source of a foreach loop.
And if that's the case you should produce a new collection, then replace it with the old one.
I would not do a "for each" method, but rather do set comparisons between the new set and old set using a HashSet (though most of this is Linq, so HashTable could be fine, IDK)
HashSet oldSet;//construct that correctly
HashSet newSet;//construct that correctly also
HashSet deletedSet = oldSet.Except(newSet);
HashSet addedSet = newSet.Except(oldSet);
Other than setting a debug variable and incrementing it every time you start the foreach, when you break in with the Visual Studio debugger connected, is there a way to tell that this is the Xth time through the loop?
I guess this would be a feature of Visual Studio if anything, not something that would be added to the compiled code.
Set a breakpoint inside the loop, then right click on the breakpoint to set the conditions. You can also right click to see the hit count while debugging and reset it if you want. You can set a boolean expression that is evaluated when the breakpoint hits to conditionally break (or just pass over).
You can also use Visual Studio's Immediate Window, which allows you to write C# expressions against any variables in scope while debugging. Use the List.IndexOf() method, like so:
Expanding on Garo Yeriazarian's answer...
A quick and dirty way without recompiling. Example code:
var ints = new[] {5, 6, 0, 1};
foreach (var i in ints)
{
Debug.WriteLine(100 / i);
}
Add one breakpoint before the loop and one inside it. When the first is hit and you want to start counting, set a Hit Count condition:
Set some large hit count condition and reset the counter and continue. Then when the exception or whatever fires, you can check the "Current hit count" again.
Heres a previous Stack Overflow question that seems to be what your looking for:
get-index-of-current-foreach-iteration
Answer quoted from that link:
Foreach is for iterating over collections that implement IEnumerable.
It does this by calling GetEnumerator on the collection, which will
return an Enumerator.
This Enumerator has a method and a property:
MoveNext()
Current
Current returns the object that Enumerator is currently on, MoveNext
updates Current to the next object.
Obviously, the concept of an index is foreign to the concept of
enumeration, and cannot be done.
Because of that, most collections are able to be traversed using an
indexer and the for loop construct.
I greatly prefer using a for loop in this situation compared to
tracking the index with a local variable.
May be you can use breakpoint hit count. Not exactly what you want, but may be helpful.
Also is there any serious reason why you don't want to use for loop in this case.
Update Feb 2017, six years later - the extension mentioned below is now called OzCode. The feature is now called Foresee, but is only supported in VS2013.
I also felt that this could be a very useful feature, so I created it as part of a commercial extension I made for the Visual Studio debugging experience called BugAid.
The extension shows you exactly which iteration you are whenever you are inside a foreach loop:
When you click the "Iteration x of y" button, you'll see a new window, showing the complete list of items, with the your current location in the loop highlighted (this list is only shown if evaluating the collection in the debugger does not cause any side effects).
Once you open ths Foreach Visualization window, you can even right click any of the upcoming items and choose "Skip to Item", to run forward until you hit that item (this can save you from manually setting-up and messing with hit-count breakpoint):
Let's say your code is
foreach (String line in lines){
Console.WriteLine(line);//breakpoint here
}
Put a breakpoint inside foreach loop, launch "Immediate window" and execute following code Array.IndexOf(lines, line);
Here's how I do it [in VS 2017] :
Set a break point inside the foreach loop
Right click the break point and select 'Actions'
In the text box, enter the following: $FUNCTION {list.Items.IndexOf(item)} where 'list' is the name of your list and 'item' is the current item
Continue running the code and watch the output window
Hit count in Visual Studio 2017:
Set the breakpoint anywhere inside the foreach loop.
Right-click your breakpoint and click "Conditions...".
Check "Conditions" box, switch dropdown to "Hit Count" and edit your Hit Count settings.
On halt, hover the breakpoint to see your settings and the Hit Count reached so far.
Don't forget that your hit count is not automatically reset to zero when you enter the loop for the 2nd time in the same session. ;-) But you can reset it manually:
Have you tried using assertion in debugging? The debugger will be launched at that exact point in your code:
For example: System.Diagnostics.Debug.Assert (myValue >=0)
If whatever you are iterating supports the IndexOf() method, you don't have to set a debug variable.
Like in this example:
foreach (var i in myList)
{
reportprogress(myList, i);
//Do stuff
}
private void reportprogress<T>(List<T> l, T i)
{
progressBar1.Value = ((l.IndexOf(i)) * 100) / l.Count;
Application.DoEvents();
}