So I'm slowly reading my way through a work book and have come to the section on enumerators. During which it gives the example code of
public class GameMoves
{
private IEnumerator _cross;
private IEnumerator _circle;
private int i;
public GameMoves()
{
_cross = Cross();
_circle = Circle();
i = I();
}
private int _move = 0;
const int MaxMoves = 9;
public int I()
{
Console.WriteLine("Test");
return (1);
}
public IEnumerator Cross()
{
while (true)
{
WriteLine($"Cross, move {_move}");
if (++_move >= MaxMoves)
{
yield break;
}
yield return _circle;
}
}
public IEnumerator Circle()
{
while (true)
{
WriteLine($"Circle, move {_move}");
if (++_move >= MaxMoves)
{
yield break;
}
yield return _cross;
}
}
}
I run this from the main method and create a new instance of this class. When the constructor runs _cross = Cross(); I expected it to work similarly to i = I(); i.e. run through the class and take the returned value. When I step through the program, it doesn't seem to activate the Cross() class at all, instead that line creates an enumerator with the value of null. Just wondering if someone could explain what that step is doing. Thanks
The whole point of iterators is exactly what you're seeing. An iterator is supposed to defer execution until the results are actually used. In your code, the I method is not an iterator so its body is executed to completion when you call it. The Cross method is an iterator so its body doesn't get executed until you use the result.
For instance, if you were to use a foreach loop to enumerate _cross you would see that each iteration of the loop would cause a yield keyword to be hit inside the Cross method. Once the yield break is hit, the method has completed and your loop would exit.
As an example of why this is good, let's compare the File.ReadAllLines method and the File.ReadLines method. The former has been around since .NET 1.0 while the latter is a much later addition. The ReadAllLines method reads the entire file and breaks it up into lines, then returns an array containing those lines. That means that you cannot start processing the file until its entire contents has been read. It also means that you must read the entire contents even if you don't need it. For instance, if there were a million lines and you wanted the first one containing a particular word, you'd have to read every line even if you found the word in the tenth line.
By contrast, the ReadLines method is an iterator. It doesn't start reading the file until you actually need the data and it only reads the data as it's needed. That means that you can process the data as it's read rather than waiting until it's all been read to start processing. It also means that you don't have to read any more data than is required, e.g. if you start looking for a word and find it on the tenth line, the remaining 999,990 lines will not be read.
Related
I am currently learning programming and often I stumble upon tasks where you type into the console indeterminate amount of lines (each is a command that I have to filter out later in main with a switch or if-else statements) and at the end you type "END" to say that you will stop writing lines (often it results in end of the program but sometimes I have to print some final code). For the longest time I have used this solution to choose the needed selection:
while (true) {
var input = Console.ReadLine().Split();
if (input[0] == "END") break;
switch (input[0]) {
//Task specific cases
}
}
but today I randomly had an idea. (After I did some research) I could add the "END" case in the switch statement using the word return. The only problem is that because my code is in main it automatically ends the program. The solution is to transfer the code to another method but is this solution better or is it a bit overcomplicated?
*Here is what the second solution looks like:
static void Main(string[] args) {
Logic();
//Other stuff to do, if the task requires it
}
public static void Logic() {
while (true) {
var info = Console.ReadLine().Split();
switch (info[0]) {
case "END": return;
//Other task specific cases
}
}
}
**Sorry if the post is confusing to read, I am not very good with programming terminology.
This is another possible implementation:
public static void Logic()
{
bool exit = false;
do
{
var info = Console.ReadLine().Split();
switch (info[0])
{
case "END":
exit = true;
break;
}
}
while (!exit);
}
Any of the solutions, to use break or to return are correct, but have different behaviors. You can use the one that you find is better.
The break statement is used to terminate the loop or statement in
which it present. After that, the control will pass to the statements
that present after the break statement, if available. If the break
statement present in the nested loop, then it terminates only those
loops which contains break statement.
The return statement terminates the execution of the method and
returns the control to the calling method. It returns an optional
value. If the type of method is void, then the return statement can be
excluded.
You can read more here: https://www.geeksforgeeks.org/c-sharp-jump-statements-break-continue-goto-return-and-throw/
Could anyone help me out by providing the solution through Recursive Methods
My Requirement is I want a recursive method, that needs to run the below code three times:
Below is my C# Working Code :
public void Process()
{
bool exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
for(int i = 0; i < 3 && exists; i++)
{
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Sleep(2000); // or long enough to ensure the uninstall process finishes executing
exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
}
Console.WriteLine(exists);
Console.ReadLine();
}
Your original code, with the for loop, does exactly what your recursive function will do. I am not too happy with posting this code. The only valid time I could think of using a recursive function, is when you are building up a Tree structure of some sorts.
You should also be aware, if you do not implement a recursive function properly, and you do not break the continuous loop you might create using recursive functions, you will run into an StackOverflow exception, due to your method being called is added to the stack, and the stack will eventually run out of memory.
Here is one way of implementing a recursive function for your needs:
public void Process(int count = 0)
{
bool exists = File.Exists("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\RevisionNumber.txt");
if (exists && count < 3)
{
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Thread.Sleep(2000); // or long enough to ensure the uninstall process finishes executing
//File exists
Console.WriteLine("File exists");
Process(++count);
}
else
{
Console.WriteLine("Exceeded retry of 3 times. File did not uninstall.");
}
if (!exists)
Console.WriteLine("File uninstalled");
}
Here is the code snippet for Recursive Method. Try it and let me know if you have any queries.
static bool FileExists(bool _fileexists, int Count)
{
//Console.WriteLine("Inside File Check");
Count++;
System.Diagnostics.Process.Start("C:\\Users\\sk185462\\Desktop\\SVNUPDATED\\SvnUninstallation.exe");
Thread.Sleep(2000);
return (_fileexists == false && Count <=3) ? FileExists(File.Exists("C:\\IFRToolLog1.txt"),Count) : true;
}
To be more specific here, please see a code snippet below.
// Consider the itemCollection has list of items
// Consider the classItems is CollectionClass that is manipulated from somewhere
foreach(var item in itemCollection)
{
List<string> someNameCollection;
bool complete = false;
// itemCollection will be have thousand of items
// First parameter is single item and item.AnyItems means IEnumerable<AnyItem>
// classItems is CollectionClass that is manipulated from somewhere
if(DoSomething(item , item.Items, classItems, out someNameCollection , out complete )){
// if someNameCollection will be empty i will fill it in DoSomework() using the same foreach() logic that is used in DoSomething()
DoSomework(someNameCollection, complete);
}
}
private bool DoSomething(Item item, IEnumerable<AnyItem> anyItems, CollectionClass classItems, out List<string> nameCollection, out bool complete )
{
bool isNeeded = false;
complete = false;
nameCollection = new List<string>();
// loop for some parameter supplied, loop will run for 100k items
foreach(var item in anyItems)
{
// may be isNeeded true here
isNeeded = true;
//if true break the loop
// complete == true, may be here
}
if(!isNeeded)
{
foreach(var item in classItems)
{
// item are any name string
nameCollection.Add(item);
}
}
// another loop doing something
foreach()
{
// uses the nameCollection here depending upon
}
foreach(var item in nameCollection)
{
foreach()
{
// play with other things here
// do some manipulations
// may be, isNeeded = true here, if true break
}
}
// and isNeeded is either true or false will only be determined may be before the end of the method
return isNeeded;
}
Now the thing is, as soon as the DoSomething() method returns it also has filled nameCollection List available. I believe that nameCollection will not be automatically garbage collected here, it will reside in the large object heap (will it be?), even though the method returns this object might not have been released from the memory (previously i have experienced this). Now again in the next call on DoSomething() the nameCollection will be filled and returned and it resides in the memory and it is not cleared, though we are creating a new instance everytime.
Do the same behavior exists as i describe above ? If not, what is the behavior here. If those collection object resides in memory, how can i flush it without affecting my out parametrized List ? If the collection object do not reside in memory, how does the out parameter get the collection object ?
It will be much more appreciated if anyone could describe me the core behavior here. I will be more than happy to clear my wrong concepts and add the right one.
The stack is one of your GC "roots". In this case, the local is formally declared in the stack-frame of the calling code (we know that because ldloca only makes sense for formally declared locals - not ambient undeclared values on the stack), so the GC doesn't have to do anything more than walk the stack-frame inspecting the locals (and the remaining stack window, but that is more complex). Ultimately, to the GC, this is no different to a local variable inside a method:
SomeObject foo = new SomeObject();
As a side note: your list allocation is redundant and wasteful, and could be just:
List<string> nameCollection;
bool complete = false;
// DoSomething will be called thousand of times
if(DoSomething(out nameCollection, complete )){ // do the further task }
However, if it was me, and DoSomething is being called thousands of times, I probably would allocate it outside the method, and treat the contents as discardable (call Clear() at the start of the method), and pass the list in - to avoid lots of list / array allocations.
I have a small command line app written in C# that uses LogParser and I was looking to clean it up a little because it is all in one massive method.
I run my query and I get a LogRecordSet object:
// run the query against wowza log
LogRecordSet logSet = logQuery.Execute(sql, new W3CInputFormat());
All good. Now I want to pass logSet into a method where I will evaluate everything:
private static IEnumerable<Unprocessed> CreateRecords(LogRecordSet logRecordset)
{
for (; !logRecordset.atEnd(); logRecordset.moveNext())
{
...
}
}
And I call it like so:
var records = CreateRecords(logSet);
This compiles fine, however it just sort of ignores the CreateRecords method, just skips over it. I admittedly know very little about c# command line applications, but I would just be interested to know why this is happening, and wasn't really sure what to google.
Edit
I have looked into a little more, and the problem seems to stem from the fact that my method uses
yield return log;
Can I not use yield return in this context?
private static IEnumerable<Unprocessed> CreateRecords(LogRecordSet logRecordset)
{
for (; !logRecordset.atEnd(); logRecordset.moveNext())
{
yield return ...;
}
}
Your CreateRecords() looks ok, just make sure you start enumerating its returned IEnumerable and you'll see it'll get invoked. For example:
var foo = CreateRecords().ToArray();
I'm new to C# and while coding a small function facing this weird problem. While using the return statement I want to return to the calling function but instead it takes me to a level before in the recursion and never exits from the recursive function.
My code is as follows:
private void findrel(String from, String to, List<RelAttr> relation)
{
String var;
List<RelAttr> temp = new List<RelAttr>();
for (int i = 0; i < relation.Count; i++)
{
if (Some Condition)
{
if (Another Condition)
{
//Do Something
paths.Add(Something);
return;
}
else
{
//Capture some value in var
paths.Add(Something);
//Move to Temp
temp.AddRange(relation);
//Remove Active Entry From Temp
temp.RemoveAt(i);
//Call with Newlist (temp)
findrel(var, to, temp);
}
}
}
//Remove Last Entry when recursion unwinds
paths.RemoveAt(paths.Count - 1);
}
I'm calling this function normally from the other function such as:
findrel(from, to, relations);
And I want the return statement to return to this function and not to a level before in the recursion. Any ideas?
The return statement will always return to the caller, and when you are using recursion this will include returning to the level above, and will not jump back to the original caller.
If you want to get right out of findrel then you will have to do something like return a flag so that the previous level knows that it should just return back to its caller and not do any more processing.
So the code will still unwind from all the calls to findrel but you will have effectively stopped processing.
Usually with recursive functions you have a terminating condition and that causes all levels of the returning function to return and this will return you to the caller. One suggestion might be to return a Boolean and terminate the recursion if that value is say false. The you can add that condition to the terminating condition of your loop and your function will exit all levels.