CLR is optimising my forloop variables away - c#

I'm trying to run a basic loop that will find a specific value in a dataview grid. I cannot figure out whats going on with the code, since the for loop exits before evaluating its basic condition.
private void SearchDataViewGrid(string FileName)
{
//finds the selected entry in the DVG based on the image
for (int i = 0; i == dataPartsList.Rows.Count ; i++)
{
if(FileName == dataPartsList.Rows[i].Cells[3].Value.ToString())
{
dataPartsList.Rows[i].Selected = true;
}
}
}
The program doesn't crash, but i get an error on my 'i' variables declaring that it has been optimised away. Tried a few easy fixes i found online but nothing seems to keep it.
I have verified that the string i am passing is the correct one, and my 'dummy' DVG returns a value of 14 for the number of rows contained. Even if i remove the 'if' statement inside of the for loop, i still get the same error.

The condition cond in the middle of for(init; cond; update) is not an until condition but a while condition.
So you need to change it to
for (int i = 0; i < dataPartsList.Rows.Count ; i++)

The problem is your conditional is i == dataPartsList.Rows.Count so the body will only execute when these two values are equal. This guarantees your loop will never execute. You need to change your conditional to be < instead of ==
for (int i = 0; i < dataPartsList.Rows.Count ; i++) {
...
}

Related

C# goto user input

I am making an OS with Cosmos and want to use goto to go to the user input but I am getting the error
No such label 'input' within the scope of the goto statement
'input' is a variable in which the user has inputted.
I can understand why this is happening but how do I fix it?
You cannot user variables as scope identifier for goto statement.. you have to use label identifier within scope (namespace) indicating it by ":" ..
for example
using System;
class Program
{
static void Main()
{
Console.WriteLine(M());
}
static int M()
{
int dummy = 0;
for (int a = 0; a < 10; a++)
{
for (int y = 0; y < 10; y++) // Run until condition.
{
for (int x = 0; x < 10; x++) // Run until condition.
{
if (x == 5 &&
y == 5)
{
goto Outer;
}
}
dummy++;
}
Outer:
continue;
}
return dummy;
}
}
method M contains three nested loops. The first loop iterates through numbers [0, 9], as do the two inner loops. But in the third loop, a condition is checked that causes the loop to exit using the break keyword.
For
Break
The code increments the dummy variable after each completion of the inner loop. If the inner loop is exited early, this variable should be left alone. With the goto statement, it is not incremented.
Result:
The value 50 is printed to the console. The int is incremented 10 x 5 times.
However:
If the goto was a break, the result would be 10 x 10 times, or a total of 100.
Hope this Help.. :)
I am making an OS with Cosmos
For getting any remotely useful answers, I think you will have to give some information about the scope of the OS. Are you only fiddling around with COSMOS a bit, or do you have some special use-case you want to serve with a custom COSMOS OS?
and want to use goto to go to the user input
Especially in the latter case (specialized OS) you should clearly refrain from using GOTO, unless you have a very good reason to do so (and in my humble opinion there is no such thing as a really good reason to use GOTO). There are viable alternatives to GOTOs in modern programming languages and you should re-think your design, algorithm, whatsoever.
To answer your question. Here is an example that produces the very error message you are experiencing
private void FirstMethod()
{
goto MyLabel;
}
private void SecondMethod()
{
MyLabel:
return;
}
I have defined a label in Method. Anyway, from Main you cannot simply jump from main to another method, since the compiler would not know where to return to, after the method has finished, since no data would have been pushed to the call stack on GOTO (please see the Wikipedia page about the call stack for further information).
The following, anyway, would work, since the label and the GOTO live within the same scope
void MyMethod()
{
goto MyLabel;
// do something
MyLabel:
return;
}

Equivalent of Ruby "redo" in C#

Is there an equivalent method of performing the job of redo in C#? i.e. going back to the top of the loop and re-execute without checking conditions or increasing the loop counter. Thanks.
for (int i = 0; i < 100; i++)
{
do
{
DoYourStuff();
} while (ShouldWeDoThatAgain());
}
Do...while is like a standard while loop, except instead of checking its conditional before each iteration, it checks after. That way, the code inside the loop will always execute at least once. Stick that inside a for or foreach loop, and that should get you the behavior your want. This is a bit simpler than Simon's answer, as it doesn't require an extra variable, doesn't use continue, and doesn't mess with the loop counter at all.
Why not simply:
Although goto is not really everyone's favourite, it's quite readable in this case...
for(...)
{
redo:
//...
if (...)
goto redo;
}
No. The closest you'll get is something like this:
bool redoCalled = false:
for (int i = 0; i < 10; i++) {
if (redoCalled) {
i--;
redoCalled = false;
}
// other stuff here
if (redoWanted) {
redoCalled = true;
continue;
}
}

assigning value to bool inside while loop

I know this is a very newbie C# question but I am implementing a small program which does the following:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
bool isRun = false;
int number = 0;
while (isRun = (true) && number < 3)
{
++number;
Console.WriteLine("Number = {0}", number.ToString());
Console.WriteLine();
}
Console.WriteLine(isRun.ToString());
Console.ReadLine();
}
}
}
At the end of the while loop, I would have expected the bool value to be true, but is is printed to be false. Why is that? Is this different from C++ where I would have done something like and the same thing in C# is giving me false
while(number<3)
{
is = true;
}
if(is){
cout<<true;
}
The reason you're seeing this behavior is due to the operator precedence involved. Here the && binds more strongly than = so the code in the loop is actually bound as the following
while (isRun = (true && number < 3)) {
...
}
Once number > 3 the && expression is false and is assigned into the isRun value and simultaneously terminates the loop. Hence once the loop exits you will see isRun as false
To get the behavior you are looking for you will need to manually correct the precedence with parens.
while ((isRun = (true)) && number < 3) {
...
}
Note: In general, as #Servey pointed out, the assignment of locals to expressions inside the loop predicate is considered bad practice. Many C# users would actually be surprised that code compiles at all because they've been conditioned to only use == in loops.
It's more idiomatic to simply set isRun to true on the first line of the loop for this pattern.
while (number < 3) {
isRun = true;
...
}
The problem is that you have set you boolean variable to false and without assigning it back to true, in while loop you are matching it against the value true, thus it fails in every case.

For loop - continue if boolean condition evaluates to false

I am writing a for loop with multiple if statements.
Is it possible that if the if statement (or one part of it) in the for statement evaluates to false, then the loop does not exit but the integer to iterates increments by one and continues through the loop (I need functionality like the continue; keyword).
Example:
for (int i = 0; i <= Collection.Count && Collection[i].Name != "Alan"; i++)
{
// If name is not Alan, increment i and continue the loop.
}
Is this possible?
Thanks
You need functionality like the continue keyword - have you considered using the continue keyword, then?
Update: Your example code is hard to decipher the intention of.
for (int i = 0; i <= Collection.Count && Collection[i].Name != "Alan"; i++)
{
// If name is not Alan, increment i.
}
The for loop has three parts to it, separated by two semi-colons. The first part initializes the loop variable(s). The second part is an expression that is evaluated each time an iteration is about to start; if it is false, the loop terminates. The third part executes after each iteration.
So your loop above will exit at the first "Alan" it encounters, and also it will increment i every time it finishes an iteration. Finally, if there are no Alans, it will execute the last time with i equal to Collection.Count, which is one larger than the maximum valid index into the collection. So it will throw an exception for sure, as you try to access Collection[i] when i is out of range.
Maybe you want this:
foreach (var item in Collection.Where(i => i.Name != "Alan"))
{
// item is not an "Alan"
}
You can think of the Where extension method as a way of filtering a collection.
If this seems obscure, you can achieve the same thing with the continue keyword (as you guessed):
foreach (var item in Collection)
{
if (item.Name == "Alan")
continue;
// item is not an "Alan"
}
Or you can just put the code in the if's block:
foreach (var item in Collection)
{
if (item.Name != "Alan")
{
// item is not an "Alan"
}
}
Do you mean like this?
for (int i = 0; i < 100; ) {
if (!condition1) {
i++;
}
if (!condition2) {
i++;
}
if (!condition3) {
i++;
}
}
Do you want the incrementor for finishing the for loop to be in the body of the loop?
I am not sure I understand correctly. You have a for loop something like this
for (int i = 0; i < 10; i++)
{
// do something
if (!b1)
i++
// do something
}
Edit:
If you use continue it increments i for only once. If you use i++ in loop it increments twice obviously. If you only want to icrement on a condition, Use the for loop like this
for (int i = 0; i < 10) // and this is very similar to a while loop.
From your sample code, I think you are searching for the name "Alan".
Is this correct?
If so, structure your loop like:
for (int i = 0; i < Collection.Count; i++)
{
if (Collection[i].Name == "Alan")
{
break; // We found the name we wanted!
}
// Otherwise: Keep going to look for the name further on.
}
if (i == Collection.Count)
{
Console.WriteLine("Alan is not found");
}
else
{
Console.WriteLine("Alan found at position {0}", i);
}

Is the condition in a for loop evaluated each iteration?

When you do stuff like:
for (int i = 0; i < collection.Count; ++i )
is collection.Count called on every iteration?
Would the result change if the Count property dynamically gets the count on call?
Yes Count will be evaluated on every single pass. The reason why is that it's possible for the collection to be modified during the execution of a loop. Given the loop structure the variable i should represent a valid index into the collection during an iteration. If the check was not done on every loop then this is not provably true. Example case
for ( int i = 0; i < collection.Count; i++ ) {
collection.Clear();
}
The one exception to this rule is looping over an array where the constraint is the Length.
for ( int i = 0; i < someArray.Length; i++ ) {
// Code
}
The CLR JIT will special case this type of loop, in certain circumstances, since the length of an array can't change. In those cases, bounds checking will only occur once.
Reference: http://blogs.msdn.com/brada/archive/2005/04/23/411321.aspx
Count would be evaluated on every pass. If you continued to add to the collection and the iterator never caught up, you would have an endless loop.
class Program
{
static void Main(string[] args)
{
List<int> intCollection = new List<int>();
for(int i=-1;i < intCollection.Count;i++)
{
intCollection.Add(i + 1);
}
}
}
This eventually will get an out of memory exception.
Yes count is checked at every call from the first iteration after the initialization of i to the last iteration where the check fails and the for loop is exited. You can modify the collections count if you want but realize you could end up in an endless loop.
Like the other answers here: Yes, in principal.
There is (at least) one noticeable exception, array.Length. In
for (int i = 0; i < a.Length; i++) a[i] = ...;
The Length property will only be evaluated once. This is a optimization that is hardwired into the compiler. There might be others like that (in the future) but only if it is guaranteed not to make a difference in observable behavior.
Side note, this is NOT checked for every interation in VB.
Unlike C#, VB caches the result of the collection.Count.
EDIT:
The literal VB version of the C# for loop is:
Dim i = 0
Do While i < collection.Count
'code goes here
i+=1
Loop

Categories

Resources