Permalänk
Medlem

Bussen c#

Hej,

Jag har också fastnat på uppdraget Bussen, som flera andra har. Jag har även läst igenom dom flesta trådarna här.
Det jag undrar är:

1. Har jag gjort rätt som har valt "private" på:

private int[] passagerare = new int[25];
private int antalPassagerare = 0;
private int maxPassagerare = 25;

Public använder man väl om man har objekt/klasser tex? Jag har ju bara en klass som är "Buss" så jag valde att ändra till private, eller är jag helt ute och cyklar nu?

2. Kan jag då ändra alla mina metoder till private också?...

3. Jag har även valt att lägga "return;" på två ställen i koden. Är det en okej lösning? Eller borde jag ändra det?

4. Tar gärna emot feedback på vad som går att förbättras.

STORT tack på förhand!

using System; namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void Run() { Console.WriteLine("Välkommen ombord på bussen!\nDu ska nu få välja ett val från menyn."); int meny; do { Console.WriteLine("\n1. Lägg till passagerare. "); Console.WriteLine("2. Kontrollera åldern på passagerarna."); Console.WriteLine("3. Beräkna sammanlagda åldern på alla passagerare."); Console.WriteLine("0.Avsluta programmet.\n"); meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(); break; case 2: utskriftPassagerare(); break; case 3: totalÅlder(); break; case 0: meny = 0; break; default: Console.WriteLine("Du har valt ett felaktigt alternativ, försök igen."); break; } } while (meny != 0); } public void adderaPassagerare() { Console.WriteLine("\nHur många passagerare vill du lägga till? "); int antal = int.Parse(Console.ReadLine()); Console.WriteLine(" "); if (antalPassagerare + antal > maxPassagerare) { int platserKvar = 25 - antalPassagerare; Console.WriteLine($"Det finns inte plats för så många passagerare, bussen rymmer 25st passagerare totalt, nu finns det {platserKvar} lediga platser kvar. "); return; } else if (antalPassagerare == passagerare.Length) //Om bussen är full kan inte någon passagerare stiga på { Console.WriteLine("Bussen är fullsatt."); return; } for (int i = 0; i < antal; i++) { Console.Write($"Du har valt att lägga till en passagerare, skriv in åldern för passageraren: "); try //Här kontrollerar vi om det är ett inmatat heltal { passagerare[antalPassagerare] = int.Parse(Console.ReadLine()); antalPassagerare++; } catch //Är det inget heltal så skrivs nedan ut { Console.WriteLine("Vänligen ange ett heltal, försök igen."); i--; // Hoppar tillbaka ett steg i indexposition. } } } public void utskriftPassagerare() //Skriv ut alla värden ur vektorn. { for (int i = 0; i < antalPassagerare; i++) { int bussplats = i + 1; // Deklarerar variabel för visa nummer på bussplats String biljettTyp = ""; if (passagerare[i] <= 20) { biljettTyp = "Barn & ungdomsbiljett."; } else { biljettTyp = "Vuxenbiljett."; } Console.WriteLine($"Passageraren på bussplats {bussplats} är {passagerare[i]} år gammal. Passageraren har åkt på: {biljettTyp}"); } if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } public void totalÅlder() { int sum = 0; for (int i = 0; i < antalPassagerare; i++) { sum += passagerare[i]; } Console.WriteLine($"\nSammanlagda åldern för alla passagerare är {sum}"); if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } class Program { public static void Main(string[] args) { //Skapar ett objekt av klassen Buss som heter minbuss var minbuss = new Buss(); minbuss.Run(); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } } }

Permalänk
Medlem

har inte skrivit c# på ett tag men försöker svara på dina frågor ändå.

1. helt rätt att göra dom private. public väljer man om man vill komma åt variabler/functioner medans man är utanför klassen.
hade du haft antalPassagerare som public tillexempel hade du kunnat skriva minbuss.antalPassagerare i din Main.
nu kommer du inte åt den variablen, vilket du inte heller vill.

2. ja du borde ändra de andra funktionerna till private om dom bara ska kallas inifrån klassen.

3. void funktioner behöver ingen return iom att du inte skickar tillbaka någonting, allmänt ska man undvika att ha 2 return i en funktion.

Permalänk
Medlem
Skrivet av interouse:

3. void funktioner behöver ingen return iom att du inte skickar tillbaka någonting, allmänt ska man undvika att ha 2 return i en funktion.

Att det är en void-funktion har ingen betydelse i det här fallet eftersom syftet inte är att returnera något utan att avsluta funktionen om det inte finns någon mening med att fortsätta, så jag skulle säga att det är helt rätt att använda return här.

Att man ska undvika flera return i en funktion är främst en gammal kvarleva från språk som t.ex. Fortran där en funktion kan returnera till flera olika ställen, vilket kunde vara väldigt felbenäget. Med tiden har det rådet förvanskats till att man inte bör returnera från flera ställen i en funktion, vilket i vissa fall fortfarande kan vara ett bra råd i språk som C när man har manuell minneshantering. I C# finns det dock sällan några fördelar med att bara ha en return per funktion, det kommer för det mesta bara krångla till koden och göra den svårare att förstå.

Permalänk
Medlem
Skrivet av perost:

Att det är en void-funktion har ingen betydelse i det här fallet eftersom syftet inte är att returnera något utan att avsluta funktionen om det inte finns någon mening med att fortsätta, så jag skulle säga att det är helt rätt att använda return här.

Att man ska undvika flera return i en funktion är främst en gammal kvarleva från språk som t.ex. Fortran där en funktion kan returnera till flera olika ställen, vilket kunde vara väldigt felbenäget. Med tiden har det rådet förvanskats till att man inte bör returnera från flera ställen i en funktion, vilket i vissa fall fortfarande kan vara ett bra råd i språk som C när man har manuell minneshantering. I C# finns det dock sällan några fördelar med att bara ha en return per funktion, det kommer för det mesta bara krångla till koden och göra den svårare att förstå.

du har helt rätt, jag läser c++ och assembly på universitetet och har där fått höra att jag enbart ska ha en return och ingen return om det är en void function så tog bara råden därifrån.

Permalänk
Medlem

Tack så hemskt mycket. Nu har jag ändrat ALLT till private?
Är min kod rätt nu? Eller borde NÅN vara public?

Då har jag kvar mina return

Sen har jag en ytterligare fråga som jag kom på, jag har ju ingen try-catch på
"Hur många passagerare vill du lägga till"
Behöver jag göra en YTTERLIGARE sån - eller kan man baka in det på nått sätt så man bara behöver en?

using System; namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void Run() { Console.WriteLine("Välkommen ombord på bussen!\nDu ska nu få välja ett val från menyn."); int meny; do { Console.WriteLine("\n1. Lägg till passagerare. "); Console.WriteLine("2. Kontrollera åldern på passagerarna."); Console.WriteLine("3. Beräkna sammanlagda åldern på alla passagerare."); Console.WriteLine("0.Avsluta programmet.\n"); meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(); break; case 2: utskriftPassagerare(); break; case 3: totalÅlder(); break; case 0: meny = 0; break; default: Console.WriteLine("Du har valt ett felaktigt alternativ, försök igen."); break; } } while (meny != 0); } private void adderaPassagerare() { Console.WriteLine("\nHur många passagerare vill du lägga till? "); int antal = int.Parse(Console.ReadLine()); Console.WriteLine(" "); if (antalPassagerare + antal > maxPassagerare) { int platserKvar = 25 - antalPassagerare; Console.WriteLine($"Det finns inte plats för så många passagerare, bussen rymmer 25st passagerare totalt, nu finns det {platserKvar} lediga platser kvar. "); return; } else if (antalPassagerare == passagerare.Length) //Om bussen är full kan inte någon passagerare stiga på { Console.WriteLine("Bussen är fullsatt."); return; } for (int i = 0; i < antal; i++) { Console.Write($"Du har valt att lägga till en passagerare, skriv in åldern för passageraren: "); try //Här kontrollerar vi om det är ett inmatat heltal { passagerare[antalPassagerare] = int.Parse(Console.ReadLine()); antalPassagerare++; } catch //Är det inget heltal så skrivs nedan ut { Console.WriteLine("Vänligen ange ett heltal, försök igen."); i--; // Hoppar tillbaka ett steg i indexposition. } } } private void utskriftPassagerare() //Skriv ut alla värden ur vektorn. { for (int i = 0; i < antalPassagerare; i++) { int bussplats = i + 1; // Deklarerar variabel för visa nummer på bussplats String biljettTyp = ""; if (passagerare[i] <= 20) { biljettTyp = "Barn & ungdomsbiljett."; } else { biljettTyp = "Vuxenbiljett."; } Console.WriteLine($"Passageraren på bussplats {bussplats} är {passagerare[i]} år gammal. Passageraren har åkt på: {biljettTyp}"); } if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } private void totalÅlder() { int sum = 0; for (int i = 0; i < antalPassagerare; i++) { sum += passagerare[i]; } Console.WriteLine($"\nSammanlagda åldern för alla passagerare är {sum}"); if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } class Program { private static void Main(string[] args) { //Skapar ett objekt av klassen Buss som heter minbuss var minbuss = new Buss(); minbuss.Run(); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } } }

Permalänk
Medlem
Skrivet av interouse:

du har helt rätt, jag läser c++ och assembly på universitetet och har där fått höra att jag enbart ska ha en return och ingen return om det är en void function så tog bara råden därifrån.

Ett enda "return" gör det enklare för andra att förvalta koden. Jag som antik inom programmering tycker det tillhör god sed att säga farväl med en return - ett medvetet val för att inte behöva fundera på om det saknas kod på slutet eller inte.

Permalänk
Medlem
Skrivet av hasenfrasen:

Ett enda "return" gör det enklare för andra att förvalta koden. Jag som antik inom programmering tycker det tillhör god sed att säga farväl med en return - ett medvetet val för att inte behöva fundera på om det saknas kod på slutet eller inte.

Att ha en och endast en "return" i en funktion, och ha den sist i funktionen, har sina fördelar - det gör det enklare att följa flödet i koden. Du vet att du börjar köra koden i början av funktionen och fortsätter till slutet. Inga undantag.

MEN! Liksom nästan alla andra regler inom programmering så är det en regel som skall användas med förnuft, och inte något som man dogmatiskt skall följa till varje pris.
Ibland blir funktioner mycket enklare att både skriva och läsa när man har flera "return" i dem. Då bör man använda flera "return".

Permalänk
Medlem
Skrivet av KodarPolle:

Tack så hemskt mycket. Nu har jag ändrat ALLT till private?
Är min kod rätt nu? Eller borde NÅN vara public?

Det är klassens interface som bör vara public, d.v.s. metoderna som användarna av klassen ska använda (variabler bör nästan aldrig vara public). I det här fallet så är i stort sett hela programmet implementerat i Buss-klassen, så det enda en användare av klassen (i det här fallet Main) behöver komma åt är Run-metoden.

Detta är dock inte en särskilt bra design, utan i ett "riktigt" program så hade Buss-klassen bara tagit hand om att hålla reda på passagerarna. En bättre design hade varit att ha menyn i t.ex. Main istället, och deklarera alla metoder som public så att de kan användas i menyn. D.v.s. istället för t.ex.:

namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void Run() { int meny; do { meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(); break; ... } } while (meny != 0); } private void adderaPassagerare() { // Läs in hur många passagerare som ska läggas till // Kolla om det finns plats // Läs in passagerare och lägg till dem i bussen } class Program { private static void Main(string[] args) { var minbuss = new Buss(); minbuss.Run(); } } } }

så skulle en vanligare design vara t.ex. så här:

namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void adderaPassagerare(int[] nyaPassagerare) { // Lägg till nya passagerare i bussen // Kanske kasta en exception eller nått om det inte finns plats } } class Program { private static void Main(string[] args) { var minbuss = new Buss(); int meny; do { meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(minbuss); break; ... } } while (meny != 0); } private void adderaPassagerare(Buss buss) { // Läs in hur många passagerare som ska läggas till // Läs in passagerare buss.adderaPassagerare(passagerare); } } }

Genom att låta Buss-klassen bara hålla reda på passagerare och låta någon annan sköta själva programlogiken så blir det betydligt enklare att återanvända Buss-klassen i andra program eller t.ex. ha flera bussar. Detta är bara ett förenklat exempel, det går att göra på många olika sätt, men det kanske ger en viss fingervisning om varför man vill ha public-metoder.

Skrivet av KodarPolle:

Sen har jag en ytterligare fråga som jag kom på, jag har ju ingen try-catch på
"Hur många passagerare vill du lägga till"
Behöver jag göra en YTTERLIGARE sån - eller kan man baka in det på nått sätt så man bara behöver en?

Du måste ha en try-catch runt varje int.Parse i din kod om du vill hantera felaktiga inmatningar, det gäller även den i din huvudmeny. Ett annat alternativ är annars att använda int.TryParse med en if-sats istället.

Permalänk
Medlem
Skrivet av KodarPolle:

if (antalPassagerare + antal > maxPassagerare) { int platserKvar = 25 - antalPassagerare; Console.WriteLine($"Det finns inte plats för så många passagerare, bussen rymmer 25st passagerare totalt, nu finns det {platserKvar} lediga platser kvar. "); return; } else if (antalPassagerare == passagerare.Length) //Om bussen är full kan inte någon passagerare stiga på { Console.WriteLine("Bussen är fullsatt."); return; }

Det här är lite nitpicking, men det där är inte en superpraktisk ordning på if-satserna, eftersom bussen aldrig kommer att beskrivas som fullsatt om användaren försöker lägga till minst en passagerare.

Dessutom är det lite otydligt att i ena fallet jämföra med maxPassagerare och i andra fallet med passagerare.Length. Som grädde på moset har du siffran 25 hårdkodad på ett par ställen, vilket gör att om man justerar värdena överst i Buss-klassen i tron att de är variabler man kan ändra så får man överraskande fel när man kör programmet.

Permalänk
Medlem
Skrivet av krfsm:

Det här är lite nitpicking, men det där är inte en superpraktisk ordning på if-satserna, eftersom bussen aldrig kommer att beskrivas som fullsatt om användaren försöker lägga till minst en passagerare.

Dessutom är det lite otydligt att i ena fallet jämföra med maxPassagerare och i andra fallet med passagerare.Length. Som grädde på moset har du siffran 25 hårdkodad på ett par ställen, vilket gör att om man justerar värdena överst i Buss-klassen i tron att de är variabler man kan ändra så får man överraskande fel när man kör programmet.

Hej,

Tack så mycket nu har jag ändrat till "maxPassagerare" istället för 25.
Har även bytt plats på min if-sats. Nu verkar det stämma va? Har testat och tycker det fungerar bra nu.

using System; namespace Bussen { class Program { private static void Main(string[] args) { //Skapar ett objekt av klassen Buss som heter minbuss var minbuss = new Buss(); minbuss.Run(); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void Run() { Console.WriteLine("Välkommen ombord på bussen!\nDu ska nu få välja ett val från menyn."); int meny; do { Console.WriteLine("\n1. Lägg till passagerare. "); Console.WriteLine("2. Kontrollera åldern på passagerarna."); Console.WriteLine("3. Beräkna sammanlagda åldern på alla passagerare."); Console.WriteLine("0.Avsluta programmet.\n"); meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(); break; case 2: utskriftPassagerare(); break; case 3: totalÅlder(); break; case 0: meny = 0; break; default: Console.WriteLine("Du har valt ett felaktigt alternativ, försök igen."); break; } } while (meny != 0); } private void adderaPassagerare() { Console.WriteLine("\nHur många passagerare vill du lägga till? "); int antal = 0; try { antal = int.Parse(Console.ReadLine()); } catch { Console.WriteLine("Vänligen ange ett heltal, försök igen."); Console.WriteLine(" "); } if (antalPassagerare + antal > maxPassagerare) { int platserKvar = maxPassagerare - antalPassagerare; Console.WriteLine($"Det finns inte plats för så många passagerare, bussen rymmer 25st passagerare totalt, nu finns det {platserKvar} lediga platser kvar. "); return; } else if (antalPassagerare == maxPassagerare) //Om bussen är full kan inte någon passagerare stiga på { Console.WriteLine("Bussen är fullsatt."); return; } for (int i = 0; i < antal; i++) { Console.Write($"Du har valt att lägga till en passagerare, skriv in åldern för passageraren: "); try //Här kontrollerar vi om det är ett inmatat heltal { passagerare[antalPassagerare] = int.Parse(Console.ReadLine()); antalPassagerare++; } catch //Är det inget heltal så skrivs nedan ut { Console.WriteLine("Vänligen ange ett heltal, försök igen."); i--; // Hoppar tillbaka ett steg i indexposition. } } } private void utskriftPassagerare() //Skriv ut alla värden ur vektorn. { for (int i = 0; i < antalPassagerare; i++) { int bussplats = i + 1; // Deklarerar variabel för visa nummer på bussplats String biljettTyp = ""; if (passagerare[i] <= 20) { biljettTyp = "Barn & ungdomsbiljett."; } else { biljettTyp = "Vuxenbiljett."; } Console.WriteLine($"Passageraren på bussplats {bussplats} är {passagerare[i]} år gammal. Passageraren har åkt på: {biljettTyp}"); } if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } private void totalÅlder() { int sum = 0; for (int i = 0; i < antalPassagerare; i++) { sum += passagerare[i]; } Console.WriteLine($"\nSammanlagda åldern för alla passagerare är {sum}"); if (antalPassagerare == 0) { Console.WriteLine("Bussen är tom."); } } } }

Uppdaterad kod
Permalänk
Medlem
Skrivet av perost:

Det är klassens interface som bör vara public, d.v.s. metoderna som användarna av klassen ska använda (variabler bör nästan aldrig vara public). I det här fallet så är i stort sett hela programmet implementerat i Buss-klassen, så det enda en användare av klassen (i det här fallet Main) behöver komma åt är Run-metoden.

Detta är dock inte en särskilt bra design, utan i ett "riktigt" program så hade Buss-klassen bara tagit hand om att hålla reda på passagerarna. En bättre design hade varit att ha menyn i t.ex. Main istället, och deklarera alla metoder som public så att de kan användas i menyn. D.v.s. istället för t.ex.:

namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void Run() { int meny; do { meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(); break; ... } } while (meny != 0); } private void adderaPassagerare() { // Läs in hur många passagerare som ska läggas till // Kolla om det finns plats // Läs in passagerare och lägg till dem i bussen } class Program { private static void Main(string[] args) { var minbuss = new Buss(); minbuss.Run(); } } } }

så skulle en vanligare design vara t.ex. så här:

namespace Bussen { class Buss { private int[] passagerare = new int[25]; private int antalPassagerare = 0; private int maxPassagerare = 25; public void adderaPassagerare(int[] nyaPassagerare) { // Lägg till nya passagerare i bussen // Kanske kasta en exception eller nått om det inte finns plats } } class Program { private static void Main(string[] args) { var minbuss = new Buss(); int meny; do { meny = int.Parse(Console.ReadLine()); switch (meny) { case 1: adderaPassagerare(minbuss); break; ... } } while (meny != 0); } private void adderaPassagerare(Buss buss) { // Läs in hur många passagerare som ska läggas till // Läs in passagerare buss.adderaPassagerare(passagerare); } } }

Genom att låta Buss-klassen bara hålla reda på passagerare och låta någon annan sköta själva programlogiken så blir det betydligt enklare att återanvända Buss-klassen i andra program eller t.ex. ha flera bussar. Detta är bara ett förenklat exempel, det går att göra på många olika sätt, men det kanske ger en viss fingervisning om varför man vill ha public-metoder.
Du måste ha en try-catch runt varje int.Parse i din kod om du vill hantera felaktiga inmatningar, det gäller även den i din huvudmeny. Ett annat alternativ är annars att använda int.TryParse med en if-sats istället.

Jag förstår..
"//SKapa ett nytt konsollprojekt med namnet "Bussen" så kan ni kopiera över all koden rakt av från denna fil" - vi fick alltså ett färdigt kodskal... färdig design som vi bara skulle fortsätta fylla i... Det är därför jag har valt att ha kvar såhär, men stort tack för hjälpen.
Jag valde dock att flytta upp class program till högst upp i koden istället för längst ner... förstår inte riktigt varför han lagt den där om jag ska vara ärlig..(?)

Har även ändrat allt till private förutom metoden Run som är public - då är det rätt va?
Försökte lägga en till try-catch runt frågan "Console.WriteLine("\nHur många passagerare vill du lägga till? ");"
Dock gick det inge bra.. ska försöka igen.