I am trying to use a while loop when using a public static class method.
I don't know where to break the loops (while and foreach).
the target is, prompting the user to enter a correct format of his name which contains all letters.
namespace Project1
{
public class Student
{
public int id;
public string name;
public string familyName;
public int age;
public static int numberOfStudents;
public static void IsAllLetter(string name)
{
while (true)
{
foreach (char c in name)
{
if (!char.IsLetter(c) || name == null)
{
break;
}
}
Console.WriteLine("name and family name must contain letters");
Console.WriteLine("please try again");
}
}
}
public class Program
{
public static void Main(string[] args)
{
// get the name
Student student1 = new Student();
Console.WriteLine("name of the student?");
student1.name = Console.ReadLine();
Student.IsAllLetter(student1.name);
}
}
}
Let's extract method, name validation:
using System.Linq;
...
// Simplest, some names like
// "Charles de Batz de Castelmore d'Artagnan"
// does not pass
private static bool IsValidName(string value) {
return
!string.IsNullOrEmpty(value) && // value can't be null or ""
value.All(letter => char.IsLetter(letter)); // All letters validation
}
Then we can implement a name input:
private static string ReadName(string title) {
while (true) {
if (!string.IsNullOrEmpty(title))
Console.WriteLine(title);
// .Trim() - let be nice and tolerate leading / trailing whitespaces
string name = Console.ReadLine().Trim();
if (IsValidName(name))
return name;
Console.WriteLine("Sorry, the name is not valid. Please, try again");
}
}
Finally, you can just use these methods in your business logic without delving into validation details:
Student student1 = new Student();
student1.name = ReadName("name of the student?");
You need only a single loop that iterates the characters in your string and return false if any "wrong" character was found:
public static bool IsAllLetter(string name)
{
if(string.IsNullOrEmpty(name))
return false;
foreach (char c in name)
{
if (!char.IsLetter(c) || name == null)
{
return false;
}
}
return true;
}
Than call that method in a loop:
string name;
while(true)
{
Console.WriteLine("name of the student?");
name = Console.ReadLine();
if(IsAllLetter(name) break;
}
Now you have a name which you can assign to your Student:
var s = new Student { Name = name };
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am making a console application and I have a "Menu" where the user can enter information to create a new Person object. The following is inside a method.
Write("Please enter the first name: ", false);
string fName = Console.ReadLine().ToUpper();
Write("Please enter the middle initial: ", false);
string mInitial = Console.ReadLine().ToUpper();
Write("Please enter the last name: ", false);
string lName = Console.ReadLine().ToUpper();
like so. I want the user to be able to exit the method at anytime if they decide they don't want to be making a new person. So I'd like to make a new method called "CheckExit" and if they type "EXIT" it will leave the "CreatePerson" method. So I want the "CheckExit" to return a return. Otherwise I have to add an "if" statement after every input and that gets clutter-y.
Is this possible? Does return have a return type? What would be the proper way to do this?
return is not a type that you can return, it's a keyword for returning a result. So unfortunately what you are trying to do is not possible.
However, you can make your code much more readable and extendable by using an array of queries and getting the results for each inside of a loop. This has the bonus effect of being able to add more queries with ease.
// you can put these queries somewhere outside the function
string[] queries = {"Please enter the first name: ", ...}
var results = new List<string>();
foreach (string query in queries) {
Write(query, false);
var result = Console.ReadLine().ToUpper();
if (result.Equals("EXIT") {
return;
}
results.Add(result);
}
// handle your inputs from the results list here ...
You could create a method to read from console to automate this process, something like
internal class StopCreatingPersonException : Exception
{}
public static string ReadFromConsole(string prompt)
{
Write(prompt, false);
var v = Console.ReadLine().ToUpper();
if (v == "EXIT") { throw new StopCreatingPerson (); }
return v;
}
Then your code would look like:
try {
string fName = ReadFromConsole("Please enter the first name: ");
....
}
catch (StopCreatingPersonException)
{ }
Return statements are used to return a value from a method that has a return type. When you write a method with void as the return type, you can use the return; to exit the method.
e.g, following method uses a string as the return type,
public string ReturnString() { return "thisString"; }
If you are writing a method that creates the object and returns it to the calling method, then the return type would be the Person (unless you intend do something else). If you check the user input and decide not to create a Person, you can use return null;.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Initial { get; set; }
}
public static Person CreatePerson()
{
Person person = new Person();
Console.Write("Please enter the first name: ", false);
string fName = Console.ReadLine().ToUpper();
if (string.IsNullOrEmpty(fName) || fName.ToLower().Equals("exit"))
return null;
person.FirstName = fName;
Console.Write("Please enter the middle initial: ", false);
string mInitial = Console.ReadLine().ToUpper();
if (string.IsNullOrEmpty(mInitial) || mInitial.ToLower().Equals("exit"))
return null;
person.Initial = mInitial;
Console.Write("Please enter the last name: ", false);
string lName = Console.ReadLine().ToUpper();
if (string.IsNullOrEmpty(lName) || lName.ToLower().Equals("exit"))
return null;
person.LastName = lName;
return person;
}
And you can use this method in the Main,
public static void Main(string[] args)
{
Person person = CreatePerson();
if (person == null) {
Console.WriteLine("User Exited.");
}
else
{
// Do Something with person.
}
}
The only way is to use return if you want to terminate method. But you can shorten your code some thing like this:
static void Main(string[] args)
{
createPerson();
Console.WriteLine("Some display goes here...");
}
static void createPerson()
{
Console.WriteLine("Please enter the first name: ");
string fName = getInput();
if (isExit(fName))
{
return;
}
Console.WriteLine("Please enter the middle initial: ");
string mInitial = getInput();
if (isExit(mInitial))
{
return;
}
Console.WriteLine("Please enter the last name: ");
string lName = getInput();
if (isExit(lName))
{
return;
}
}
static string getInput()
{
return Console.ReadLine().ToUpper();
}
static bool isExit(string value)
{
if (value == "EXIT")
{
Console.WriteLine("Create person has been canceled by the user.");
return true;
}
return false;
}
I don't really understand arrays and I need to create a variable of type 'array of songs' then initialize it to a new Array so it can store 4 references to Songs. How would I then create a loop that would run enough times to fill the array whilst calling the InputSOngDetails() method and store the return value in that method?
namespace Songs
{
class Program
{
static void Main(string[] args) {
InputSongDetails();
}
static Song InputSongDetails()
{
Console.WriteLine("What is the name of your song");
string name = Console.ReadLine();
Console.WriteLine("What is the artists name");
string artist = Console.ReadLine();
int records;
Console.WriteLine("How many records did it sell");
while (!int.TryParse(Console.ReadLine(), out records) || records < 0)
{
Console.WriteLine("That is not valid please enter a number");
}
return new Song(name, artist, records);
}
}
}
This is my Songs class if needed
namespace Songs
{
class Song
{
string name;
string artist;
int copiesSold;
public Song(string name, string artist, int copiesSold)
{
this.name = name;
this.artist = artist;
this.copiesSold = copiesSold;
}
public Song()
{
}
public string GetArtist()
{
return artist;
}
public string GetDetails()
{
return $"Name: {name} Artist: {artist} Copies Sold: {copiesSold},";
}
public string GetCertification()
{
if (copiesSold<200000)
{
return null;
}
if (copiesSold<400000)
{
return "Silver";
}
if (copiesSold<600000)
{
return "gold";
}
return "Platinum";
}
}
}
Fist, initialize your array of songs with new Song[ length ], then a simple for-loop will suffice.
static void Main(string[] args)
{
Song[] songs = new Song[4];
for(int i = 0; i < songs.Length; i++)
{
songs[i] = InputSongDetails();
}
}
Or as the commenters suggest, just use a variable-length List<Song>.
static void Main(string[] args)
{
List<Song> songs = new List<Song>();
for(int i = 0; i < 4; i++)
{
songs.Add(InputSongDetails());
}
}
Once you've mastered the basics, you can also accomplish this with a bit of Linq (though I wouldn't actually recommend it in this case):
static void Main(string[] args)
{
var songs = Enumerable.Range(0, 4)
.Select(i => InputSongDetails())
.ToList();
}
This is not really an answer as much as it is a tip for getting input from the user in a console application which might be useful to you (well, the answer is in the last code snippet, but p.s.w.g has already covered that very well).
Since an interactive console session usually ends up with a lot of Console.WriteLine("Ask the user a question"); string input = Console.ReadLine();, and, as you've already done very well, include some validation on the input in some cases, I've found it handy to write the following methods below.
Each of them take in a string, which is the prompt for the user (the question), and return a strongly-typed variable that represents their input. Validation (when needed) is all done in a loop in the method (as you've done):
private static ConsoleKeyInfo GetKeyFromUser(string prompt)
{
Console.Write(prompt);
var key = Console.ReadKey();
Console.WriteLine();
return key;
}
private static string GetStringFromUser(string prompt)
{
Console.Write(prompt);
return Console.ReadLine();
}
public static int GetIntFromUser(string prompt = null)
{
int input;
int row = Console.CursorTop;
int promptLength = prompt?.Length ?? 0;
do
{
Console.SetCursorPosition(0, row);
Console.Write(prompt + new string(' ', Console.WindowWidth - promptLength - 1));
Console.CursorLeft = promptLength;
} while (!int.TryParse(Console.ReadLine(), out input));
return input;
}
With these methods in place, getting input is as simple as:
string name = GetStringFromUser("Enter your name: ");
int age = GetIntFromUser("Enter your age: ");
And it makes writing the method to get a Song from the user that much easier:
private static Song GetSongFromUser()
{
return new Song(
GetStringFromUser("Enter song name: "),
GetStringFromUser("Enter Artist name: "),
GetIntFromUser("Enter number of copies sold: "));
}
So now our main method just looks like (and this is the answer to your question):
private static void Main()
{
var songs = new Song[4];
for (int i = 0; i < songs.Length; i++)
{
songs[i] = GetSongFromUser();
}
Console.WriteLine("\nYou've entered the following songs: ");
foreach (Song song in songs)
{
Console.WriteLine(song.GetDetails());
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Additionally, here are some suggestions for improving the Song class.
I'm practicing on setters and getters, got this error message:
Cannot assign to 'GetnewName' because it is a'method group'
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
Bird b = new Bird();
b.GetnewName = "Tweety";
b.Chirp();
Bird b2 = new Bird();
b2.GetnewName = "Woody";
b2.Chirp();
}
}
public class Bird
{
private string name;
private double weight = 30.5d;
public void SetName(string newName)
{
if (newName != null && newName.Length > 2)
{
System.Console.WriteLine("Bird already has a name");
this.name = newName;
}
else if (newName.Length < 3)
{
System.Console.WriteLine("New name must be longer than two chars");
}
else
{
name = newName;
}
}
public string GetnewName()
{
return this.name;
}
public void Chirp()
{
System.Console.WriteLine(name + " says chirp!");
}
}
}
You need to set name using the SetName method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
Bird b = new Bird();
b.SetName("Tweety");
b.Chirp();
Bird b2 = new Bird();
b2.SetName("Woody");
b2.Chirp();
Console.ReadLine();
}
}
public class Bird
{
private string name;
private double weight = 30.5d;
public void SetName(string newName)
{
if (newName != null && newName.Length > 2)
{
System.Console.WriteLine("Bird already has a name");
this.name = newName;
}
else if (newName.Length < 3)
{
System.Console.WriteLine("New name must be longer than two chars");
}
else
{
name = newName;
}
}
public string GetnewName()
{
return this.name;
}
public void Chirp()
{
System.Console.WriteLine(name + " says chirp!");
}
}
}
You are using GetnewName as if it were a property, but you defined it as a pair of methods.
Property syntax combines the getter and the setter under a single name. Then C# re-routs assignments to the setter, and reads to the getter method:
public string Name {
get => name
set {
if (value != null && value.Length > 2) {
System.Console.WriteLine("Bird already has a name");
name = value;
} else if (value.Length < 3) {
System.Console.WriteLine("New name must be longer than two chars");
} else {
name = value;
}
}
}
Note: get => name above uses the new syntax. Old syntax for the same was get { return name; }
You cannot assign a string to a method, this causes the error.
I c# we don't use getters and setters as in Java or C++. Instead we have properties which we use. You can assign and read values as if they where fields but they have special methods called accessors. You should refactor your class like this:
public class Bird
{
private string name;
private double weight = 30.5d;
public string Name
{
get => name;
set
{
if (value != null && value.Length > 2)
{
Console.WriteLine("Bird already has a name");
name = value;
}
else if (value != null && value.Length < 3)
{
Console.WriteLine("New name must be longer than two chars");
}
else
{
name = value;
}
}
}
public void Chirp()
{
System.Console.WriteLine(name + " says chirp!");
}
}
Then you can use it as:
var bird = new Bird();
// assign a value (equivalent to SetName method in your original code)
bird.Name = "Woody";
// read a value (equivalent to GetName method in your original code)
Console.WriteLine(bird.Name);
It seems like you want this:
public string Name
{
get; private set;
}
public void SetName(string newName)
{
if (newName != null && newName.Length > 2)
{
System.Console.WriteLine("Bird already has a name");
Name = newName;
}
else if (newName.Length < 3)
{
System.Console.WriteLine("New name must be longer than two chars");
}
else
{
Name = newName;
}
}
The get; will automatically return the value of your property, without the need for a private backing property, and typically you could use the setter inside the property to set the value, but since you need to pass a parameter too it, it seems like making the setter private and creating a separate method to actually set it would suit your needs.
I'm trying to create menu for my simple app. I want to use switch but I can't find a way to call functions in uninstanced class which is instanced on application startup.
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
this.mainMenu();
}
public void mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
break;
How do I call MainLibrary's function in case 1. It's obviously not instanced here but I can't find a way pass reference to uninstanced object.
BookList code :
class BookList
{
List<Book> books = new List<Book>();
public void addBook() // adding book
{
string name = Console.ReadLine();
string author = Console.ReadLine();
int relDate = int.Parse(Console.ReadLine());
int uID = books.Count() + 1;
books.Add(new Book(name, author, relDate, uID));
}
public void deleteBook() // deleting book
{
int readForDelete = int.Parse(Console.ReadLine());
books.RemoveAll(Book => Book.UniqueID == readForDelete);
}
public void borrowBook() // borrowing book
{
int readForBorrow = int.Parse(Console.ReadLine());
foreach (Book Book in books)
{
if (Book.UniqueID == readForBorrow)
Book.available = false;
}
}
public void returnBook() // returning book
{
int readForReturn = int.Parse(Console.ReadLine());
foreach (Book Book in books)
{
if (Book.UniqueID == readForReturn)
Book.available = true;
}
}
public void displayBooks() // displaying list of books
{
string isAvailable;
foreach (Book Book in books)
{
if (Book.available == true)
isAvailable = "available";
else
isAvailable = "unavailable";
Console.WriteLine(" {0} {1} {2} {3} {4} ", Book.UniqueID, Book.BookName, Book.BookName, Book.ReleaseDate, isAvailable);
}
}
public string Name
{
get; set;
}
}
}
You either need to pass your BookList instance to your mainMenu() method, or set a global variable. I'd recommend the former.
public void mainMenu(BookList list) { ... }
Then call it like this from startLibrary:
this.mainMenu(MainLibrary);
As a side note, you really need to brush up on your variable, class, and method naming conventions.
You could implement it with lambdas like this:
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
Action<BookList> action = this.mainMenu();
if (action != null)
{
action(MainLibrary);
}
}
public Action<BookList> mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
return b => b.addBook();
}
Or you could just pass a reference to your MainLibrary variable to the method:
class Window
{
public void startLibrary(int sizeX, int sizeY)
{
BookList MainLibrary = new BookList();
this.mainMenu(MainLibrary);
}
public Action<BookList> mainMenu(BookList b)
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
b.addBook();
break;
}
First of all, what you've got in your startLibrary method is a local variable - which is accessible only within the block it's defined in. That said, the MainLibrary is not something you can reference from anywhere else.
To solve your problem you have several options.
You can make the MainLibrary a field/member of the Window class. Then all the instance methods of the Window class will have access to it - so as the MainMenu method:
class Window
{
private BookList MainLibrary;
public void startLibrary(int sizeX, int sizeY)
{
this.MainLibrary = new BookList();
this.mainMenu();
}
public void mainMenu()
{
string userChoice = Console.ReadLine();
switch (userChoice)
{
case "1":
// do whatever you want with this.MainLibrary here
break;
/// ...
}
}
}
The other option would be to pass in the MainLIbrary instance you've created into the mainMenu method. Here you'll need to update the signature of the method as follows:
public void mainMenu(BookList list)
{
// reference the list now as necessary
}
I want to limit my string, so that you have to put a minimum of 3 chars and a max of 10 chars in. Is this possible in the following code below?
main.cs:
class Program
{
static void Main(string[] args)
{
Something hello = new Something();
string myname;
Something test = new Something();
myname = Console.ReadLine();
test.Name = myname;
}
}
class with properties:
class Okay : IYes
{
private string thename;
public string Name
{
get {return thename;}
set {thename = value;} //what to put here???
}
}
The setter is probably not the best place to check. You should make the check at the point of input:
string myname = "";
while (myname.Length<3 || myname.Length >10)
{
Console.WriteLine("Please enter your name (between 3 and 10 characters");
myname = Console.ReadLine();
}
test.Name = myname;
Obviously you can take some steps to make this more user friendly: maybe a different message after the first failure, some way of getting out of the loop, etc.
Try this:-
public string Naam
{
get { return thename; }
set
{
if (value.Length >= 3 && value.Length <= 10)
thename = value;
else
throw new ArgumentOutOfRangeException();
}
}
class Okay : IYes
{
private string name;
public string Name
{
get { return name; }
set
{
if (value == null) throw new ArgumentNullException("Name");
if (value.Length < 3 || value.Length > 10)
throw new ArgumentOutOfRangeException("Name");
name = value;
}
}
}
You can also truncate the string if it's too long, rather than throwing an exception by just taking (up to) the first 10 characters:
class Okay : IYes
{
private string name;
public string Name
{
get { return name; }
set
{
if (value == null) throw new ArgumentNullException("Name");
if (value.Length < 3) throw new ArgumentOutOfRangeException("Name");
name = string.Join("", value.Take(10));
}
}
}
private static void GenericTester()
{
Okay ok = new Okay {Name = "thisIsLongerThan10Characters"};
Console.WriteLine(ok.Name);
}
// Output:
// thisIsLong