IEnumerable - Move Next - c#

I have an IEnumerable from which I need to fetch each item and display it one by one. The displaying is not a continuous process..i.e I should fetch one item and display it on the UI, then wait for some user feedback on that item, and then move on to the next item. For example from the below code, I need to fetch a question, then display it to the user, then user hits enter, and then I move on to fetching the next question.
My Question is how do I do that? Is IEnumerable the best way of achieving this or should I revert to list and start storing the indexes and increment it one by one?
Please note that I'm using .NET 3.5.
Code:
class Program
{
static void Main(string[] args)
{
Exam exam1 = new Exam()
{
Questions = new List<Question>
{
new Question("question1"),
new Question("question2"),
new Question("question3")
}
};
var wizardStepService = new WizardStepService(exam1);
var question = wizardStepService.GetNextQuestion();
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
}
}
public class Question
{
private readonly string _text;
public Question(string text)
{
_text = text;
}
public string Content { get { return _text; } }
}
internal class Exam
{
public IEnumerable<Question> Questions { get; set; }
}
internal class WizardStepService
{
private readonly Exam _exam;
public WizardStepService(Exam exam)
{
_exam = exam;
}
public Question GetNextQuestion()
{
foreach (var question in _exam.Questions)
{
//This always returns the first item.How do I navigate to next
//item when GetNextQuestion is called the second time?
return question;
}
//should have a return type hence this or else not required.
return null;
}
}

Yes, GetEnumerator() should work fine; although strictly speaking you need to handle Dispose():
internal class WizardStepService : IDisposable
{
private IEnumerator<Question> _questions;
public WizardStepService(Exam exam)
{
_questions = exam.Questions.GetEnumerator();
}
public void Dispose()
{
if (_questions != null) _questions.Dispose();
}
public Question GetNextQuestion()
{
if (_questions != null)
{
if (_questions.MoveNext())
{
return _questions.Current;
}
Dispose(); // no more questions!
}
//should have a return type hence this or else not required.
return null;
}
}
and also:
using (var wizardStepService = new WizardStepService(exam1))
{
var question = wizardStepService.GetNextQuestion();
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
}
However, since you're not actually testing the result each time, you could also do something like:
using (var questions = exam1.Questions.GetEnumerator())
{
questions.MoveNext();
var question = questions.Current;
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
questions.MoveNext();
question = questions.Current;
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
questions.MoveNext();
question = questions.Current;
Console.WriteLine(question.Content);
Console.ReadLine();
}
Or as a final thought, perhaps just:
var questions = exam1.Questions.Take(3).ToArray();
//Should output question1
Console.WriteLine(questions[0].Content);
Console.ReadLine();
//Should output question2 but outputs question1
Console.WriteLine(questions[1].Content);
Console.ReadLine();
//Should output question3 but outputs question1
Console.WriteLine(questions[2].Content);
Console.ReadLine();

Well you could store an IEnumerator<T> instead, and change GetNextQuestion to:
return _exam.MoveNext() ? _exam.Current : null;
However, at that point you're not actually adding any value with the Exam or WizardStepService classes, and you might as well just use IEnumerator<T> directly in Main. Note that your Main method itself is a little odd - it has repeated code where a foreach loop would be simpler - and you're unconditionally asking three questions.
Note that if you have a type with an IEnumerator<T> as a field, you probably want to implement IDisposable in order to dispose of the iterator, too - it all gets a bit messy.

Try this:
class Program2
{
static void Main(string[] args)
{
Exam exam1 = new Exam()
{
Questions = new List<Question>
{
new Question("question1"),
new Question("question2"),
new Question("question3")
}
};
var wizardStepService = new WizardStepService(exam1);
foreach (var question in wizardStepService.GetQuestions())
{
Console.WriteLine(question.Content);
Console.ReadLine();
}
}
}
public class Question
{
private readonly string _text;
public Question(string text)
{
_text = text;
}
public string Content
{
get
{
return _text;
}
}
}
internal class Exam
{
public IEnumerable<Question> Questions
{
get;
set;
}
}
internal class WizardStepService
{
private readonly Exam _exam;
public WizardStepService(Exam exam)
{
_exam = exam;
}
public IEnumerable<Question> GetQuestions()
{
foreach (var question in _exam.Questions)
{
//This always returns the first item.How do I navigate to next
//item when GetNextQuestion is called the second time?
yield return question;
}
//should have a return type hence this or else not required.
//return null;
}
}

Related

Crash when class write to console

I'm going to get another user and enter which month he wants and find the quarter.
Thought of writing the code inside a class as I need more training on how to use classes.
The program asks whose month it is and I can enter. But now when I type "January" only programs crash.
I assume that it should show which quarter "january" is in
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Write a month");
var mc = new MyClass();
mc.month = Convert.ToString(Console.ReadLine());
}
public class MyClass
{
public string month;
public string Prop
{
get
{
return month;
}
set
{ if (Prop == "january")
{
Console.WriteLine("1.quarter");
}
}
}
}
}
}
Consider presenting a menu which in the case below uses a NuGet package Spectre.Console and docs. This gives you an opportunity to work with classes and ensures, in this case input is a valid month along with reties and how to exit.
First a class for the menu.
public class MonthItem
{
public int Index { get; }
public string Name { get; }
public MonthItem(int index, string name)
{
Index = index;
Name = name;
}
public override string ToString() => Name;
}
Class which creates the menu
class MenuOperations
{
public static SelectionPrompt<MonthItem> SelectionPrompt()
{
var menuItemList = Enumerable.Range(1, 12).Select((index) =>
new MonthItem(index, DateTimeFormatInfo.CurrentInfo.GetMonthName(index)))
.ToList();
menuItemList.Add(new MonthItem(-1, "Exit"));
SelectionPrompt<MonthItem> menu = new()
{
HighlightStyle = new Style(Color.Black, Color.White, Decoration.None)
};
menu.Title("[yellow]Select a month[/]");
menu.PageSize = 14;
menu.AddChoices(menuItemList);
return menu;
}
}
Present menu, get selection and show details or exit.
static void Main(string[] args)
{
while (true)
{
Console.Clear();
var menuItem = AnsiConsole.Prompt(MenuOperations.SelectionPrompt());
if (menuItem.Index != -1)
{
AnsiConsole.MarkupLine($"[b]{menuItem.Name}[/] index is [b]{menuItem.Index}[/]");
Console.ReadLine();
}
else
{
return;
}
}
}
I tested your code and your program is not crashing. The program is actually completing and therefore the console is closing due to execution completing. So you can see what I mean try changing your code to this. You will see your code loop and the console will not close. It will also display what the user types in for mc.month
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("Write a month");
var mc = new MyClass();
mc.month = Convert.ToString(Console.ReadLine());
Console.WriteLine(mc.month);
}
}
On a side note, not really how I would use a class. You might want to also rethink that. Don't normally see writelines in class.

How to pass value in ArrayList from method to method

public Program()
{
amount_bike = new ArrayList();
}
public void push(int value)
{
this.amount_bike.Add(value);
}
public int amount_bike_pop()
{
if (this.amount_bike.Count == 0)
{
return -100000;
}
int lastItem = (int)this.amount_bike[this.amount_bike.Count - 1];
this.amount_bike.RemoveAt(this.amount_bike.Count - 1);
return lastItem;
}
public static void Bike_status()
{
bool exit = false;
Program available = new Program();
available.push(0);
available.push(0);
available.push(50);
WriteLine("E-bike available for rent is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Rented E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("Broke E-bike is : " + available.amount_bike_pop() + " bikes.");
WriteLine("\n");
WriteLine("Please enter a number: 1 is back to pervoius menu or 0 to Exit");
int input = Convert.ToInt32(ReadLine());
while (exit == false)
{
if (input == 1)
{
Clear();
exit = true;
continue;
}
else if (input == 0)
{
Clear();
Exit();
}
else
{
Clear();
Bike_status();
}
}
}
public static void Add_bike()
{
}
I study data structures and Algorithms. In this code, I keep the value in an ArrayList named "available" in the Bike_status method. I need to pass a value in an ArrayList to the Add_bike method. How do I pass a value from one method to another? Actually, I need to pass valus such as 50 to plus some number that I push in Console.ReadLine.
Try to slow down.at starting point of programming sometimes it's confusing.
How do I pass a value from one method to another?
The simple answer is easy ,you want something to use in the function then in your method(s) you create parameter and pass the things you want to it.
like
//edit method to get int value -> public static void Bike_status()
public static void Bike_status(int value)
//edit when to call
else
{
Clear();
Bike_status(input);//send int value in
}
But really, what is that do you really want to learn?
if it OOP? I recommend you study this
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/
To put it simply you has bicycle shop class separate from main program then use the method in that class
e.g.
//bicycle class
public class Bicycles{
public int ID {get;set;}
pulibc string status {get;set; }
public Bicycles(int p_id, string p_status)
{
ID = p_id;
status=p_status;
}
}
//bicycle shop class
public class BicyclesShop{
public List<Bicycle> available {get;set;} // class member
public BicyclesShop() // go search keyword "constructor"
{
available = new List<Bicycle> ();
}
//other method
public void Add_bike()
{
// I can access available object !
// do anything with this class member(s) !
}
public void Bike_status(int inputVal)
{
// do something with inputVal , change some properties?
}
//other methods
public int amount_bike_pop()
{
return available.Count();
}
public int amount_bike_broken_pop()
{
return available.Where(o=>o.status =="Broken").Count(); // go search linq
}
}
//To use in Main program method
BicyclesShop bs =new BicyclesShop();
bs.available.Add( new Bicycle(1 ,"OK") ); //add bicycle #1 in list
bs.available.Add( new Bicycle(2),"Broken" ); //add bicycle #2 in list
WriteLine("Broke E-bike is : " + bs.amount_bike_broken_pop() + " bikes.");

problem with my array class error CS0120 C# [duplicate]

This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 3 years ago.
I'm still learning to code so if there are some issues, please tell me! This is for a school essay.
I'm writing a code that asks some information about a game: game name, the devs behind it, the publisher, and its cost.
The essay has multiple different tasks, like: make a program that uses get set, arrays, methods, or and so on. I made it all into a program, and I got stuck with the error
CS0120 An object reference is required for the non-static field, method, or property 'Program.gameInfoArray'
The code:
class Program
{
//the class array that stores the games
public gameInfo[] gameInfoArray = new gameInfo[10];
static void Main(string[] args)
{
bool done = false;
// this is where i get the issue
for (int i = 0; i >= gameInfoArray.Length || done == false; i++)
{
//asks what the game is called
Console.WriteLine("What is the game called:");
string gameName = Console.ReadLine();
//asks who the devolopers are
Console.WriteLine("Who where the devolopers behind the game:");
string devoloper = Console.ReadLine();
//asks who published the game
Console.WriteLine("Who released the game:");
string publisher = Console.ReadLine();
//ask how much the game costs
Console.WriteLine("How much does the game cost:");
string cost = Console.ReadLine();
//inputs the information in to the class array, this is also where i get the issue
gameInfoArray[i].gameInformationGrabber(gameName, devoloper, publisher, cost);
//asks if the
Console.WriteLine("are there any more games? Y/N");
while(true)
{
ConsoleKeyInfo yesOrNo = Console.ReadKey();
if ((yesOrNo.KeyChar == 'Y') || (yesOrNo.KeyChar == 'y'))
{
done = true;
break;
}
else if ((yesOrNo.KeyChar == 'N') || (yesOrNo.KeyChar == 'n'))
{
break;
}
}
}
}
}
The script:
class gameInfo
{
private string gameName;
private string devoloper;
private string publisher;
private string cost;
public void gameInformationGrabber(string game, string dev, string publisher, string cost)
{
theGameName = game;
theDevs = dev;
thePublisher = publisher;
theCost = cost;
}
public string theGameName
{
get { return gameName; }
set { gameName = value; }
}
public string theDevs
{
get { return devoloper; }
set { devoloper = value; }
}
public string thePublisher
{
get { return publisher; }
set { publisher = value; }
}
public string theCost
{
get { return cost; }
set { cost = value; }
}
}
Thanks a ton in advance. Sorry if I messed up big time somewhere in the code.
You've got two comment, it is perfect solution for you.
I hope you spend a time to get a basic concept from it.
However, this will help you.
1. Static only
This is a solution mentioned comment.
class Program
{
// Add static keyword. Because Main() method is static.
// So, every variable inside it should be static.
// public gameInfo[] gameInfoArray = new gameInfo[10];
public static gameInfo[] gameInfoArray = new gameInfo[10];
static void Main(string[] args)
{
......
}
}
2. Work with local variable
class Program
{
//public gameInfo[] gameInfoArray = new gameInfo[10];
static void Main(string[] args)
{
// Declare as local variable.
// In static method will now complain using local variable.
gameInfo[] gameInfoArray = new gameInfo[10];
......
}
}
I've tried to run this code, plase don't forget initialize gameInfoArray to prevent null reference exception.
you may need this before entering for loop,
for (int index = 0; index < gameInfoArray.Length; index++)
{
gameInfoArray[index] = new gameInfo();
}

Replacing/changing a blank or null string value in C#

I've got something like this in my property/accessor method of a constructor for my program.
using System;
namespace BusinessTrips
{
public class Expense
{
private string paymentMethod;
public Expense()
{
}
public Expense(string pmtMthd)
{
paymentMethod = pmtMthd;
}
//This is where things get problematic
public string PaymentMethod
{
get
{
return paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(" "))
paymentMethod = "~~unspecified~~";
else paymentMethod = value;
}
}
}
}
When a new attribute is entered, for PaymentMethod, which is null or a space, this clearly does not work. Any ideas?
do you perhaps just need to replace string.IsNullOrWhiteSpace(" ") with string.IsNullOrWhiteSpace(value) ?
From your posted code, you need to call:
this.PaymentMethod = pmtMthd;
instead of
paymentMethod = pmtMthd;
The capital p will use your property instead of the string directly. This is why it's a good idea to use this. when accessing class variables. In this case, it's the capital not the this. that makes the difference, but I'd get into the habit of using this.
Jean-Barnard Pellerin's answer is correct.
But here is the full code, which I tested in LinqPad to show that it works.
public class Foo {
private string _paymentMethod = "~~unspecified~~";
public string PaymentMethod
{
get
{
return _paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(value))
_paymentMethod = "~~unspecified~~";
else _paymentMethod = value;
}
}
}
With a main of:
void Main()
{
var f = new Foo();
f.PaymentMethod = "";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = " ";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = "FooBar";
Console.WriteLine(f.PaymentMethod);
}
Output from console:
~~unspecified~~
~~unspecified~~
FooBar

Aggregation. Linq to objects query

I have 3 classes
public class Test
{
private List<Question> _questions;
private string _text;
public string Text
{
get
{
return _text;
}
}
//...
}
public class Question
{
private List<Answer> _answers;
private string _text;
public string Text
{
get
{
return _text;
}
}
//...
}
public class Answer
{
private string _text;
private bool _isCorrect;
public string Text
{
get
{
return _text;
}
}
public bool isCorrect
{
get
{
return _isCorrect;
}
}
//...
}
I need to select a Text from Questions and Text from Answers, where Answer is correct.
I can only select correct Answers.
Test t;
//Initializing t
var r = t.SelectMany<Question, Answer>(q => q).Where<Answer>(a => a.isCorrect == true);
My question is:
How to select a Text from Questions and Text from Answers, where Answer is correct.
I need to make a linq to objects query.
Assuming Test implements IEnumerable<Question> and Question implements IEnumerable<Answers>:
var questionsWithCorrectAnswers = myTest
.SelectMany(q => q.Where(a => a.IsCorrect)
.Select(a => new { Question = q, Answer = a }));
First off, your Questions and Answers are private. I'll assume you have a public accessor Questions and Answers, respectively.
Try this:
var results = from q in t.Questions
where q.Answers.Any(a=>a.isCorrect)
select new {Question = q, CorrectAnswers = q.Answers.Where(a=>a.isCorrect)};
You can now reference results.Question and results.CorrectAnswers. You can also select a new Question where the Answers list contains only correct Answers.

Categories