CS_LEVEL_11_SOLUTION - OnlyCook/abitur-elite-code GitHub Wiki
public class Klasse
{
private string bezeichnung;
private List<Schueler> schuelerListe;
public Klasse(string bez)
{
this.bezeichnung = bez;
this.schuelerListe = new List<Schueler>();
}
public void AddSchueler(Schueler s)
{
schuelerListe.Add(s);
}
public double BerechneSchnittBestanden()
{
if (schuelerListe.Count == 0) return 0.0;
int bestanden = 0;
int notenSumme = 0;
foreach (Schueler s in schuelerListe)
{
if (s.GetNote() > 4)
{
bestanden++;
notenSumme += s.GetNote();
}
}
if (bestanden == 0) return 0.0;
return (double)notenSumme / bestanden;
}
}
public class Schueler
{
private int note;
public Schueler(int note)
{
this.note = note;
}
public int GetNote()
{
return note;
}
}Dieses Level ist der Einstieg in Sektion 3: Beziehungen & Navigation. Zum ersten Mal implementierst du nicht nur eine Klasse, sondern zwei Klassen, die miteinander zusammenarbeiten: Klasse kennt Schueler – und zwar mehrere davon, gespeichert in einer Liste.
Im UML-Diagramm ist das durch die Assoziation Klasse --> * Schueler ausgedrückt: Eine Klasse hat beliebig viele Schüler.
public class Schueler
{
private int note;
public Schueler(int note)
{
this.note = note;
}
public int GetNote()
{
return note;
}
}Schueler ist bewusst einfach gehalten – ein einzelnes Attribut, ein Konstruktor, eine Getter-Methode. Das Attribut note ist private, also von außen nicht direkt zugreifbar. Der Zugriff läuft ausschließlich über GetNote(). Das ist das Standard-Muster im Abitur.
public Klasse(string bez)
{
this.bezeichnung = bez;
this.schuelerListe = new List<Schueler>();
}Wichtig: Die Liste schuelerListe wird im Konstruktor initialisiert – nicht bei der Deklaration. Das ist die im Abitur erwartete Schreibweise. Ohne diese Zeile wäre schuelerListe null, und jeder Aufruf von .Add() würde sofort mit einem Laufzeitfehler scheitern.
AddSchueler(Schueler s) ist die übliche Hilfsmethode, um Objekte von außen in die interne Liste einzutragen.
Hier liegt die eigentliche Herausforderung. Die Methode soll den Notendurchschnitt berechnen – aber nur für Schüler, die bestanden haben (Note > 4).
if (schuelerListe.Count == 0) return 0.0;Bevor irgendetwas berechnet wird, prüfen wir: Gibt es überhaupt Schüler? Wenn nicht, gibt es nichts zu berechnen – direkt 0.0 zurückgeben.
int bestanden = 0;
int notenSumme = 0;
foreach (Schueler s in schuelerListe)
{
if (s.GetNote() > 4)
{
bestanden++;
notenSumme += s.GetNote();
}
}Wir laufen mit einer foreach-Schleife durch alle Schüler. Für jeden Schüler, der bestanden hat (Note strikt größer als 4), erhöhen wir den Zähler bestanden um 1 und addieren seine Note zur Summe. Schüler, die nicht bestanden haben, werden komplett ignoriert.
Warum nicht einfach schuelerListe.Count als Teiler nehmen?
Weil dann auch nicht bestandene Schüler den Durchschnitt beeinflussen würden – das wäre logisch falsch. Wir teilen nur durch die Anzahl der Schüler, die tatsächlich in die Summe eingegangen sind.
if (bestanden == 0) return 0.0;Wenn zwar Schüler vorhanden sind, aber keiner bestanden hat, wäre bestanden == 0. Eine Division durch 0 führt in C# bei int-Division zu einem Laufzeitfehler. Dieser Fall wird daher vorher explizit abgefangen.
return (double)notenSumme / bestanden;Beide Variablen – notenSumme und bestanden – sind vom Typ int. Eine Division zweier int-Werte ergibt in C# immer ein ganzzahliges Ergebnis (z.B. 7 / 2 = 3, nicht 3.5). Der Cast (double) sorgt dafür, dass die Division als Gleitkommazahl ausgeführt wird und Nachkommastellen erhalten bleiben.
| Schritt | Was passiert? |
|---|---|
| Liste leer? | Sofort 0.0 zurückgeben |
foreach-Schleife |
Nur bestandene Schüler zählen und summieren |
| Niemand bestanden? | Sofort 0.0 zurückgeben |
| Sonst | Summe durch Anzahl teilen (mit Cast auf double) |