Zum Hauptinhalt springen

C#

Zusammenfassung

// short constructor directly in the class definition
public class Rectangle(int width, int height) : Shape("Rectangle")) {
// properties
public int Width { get; } = width;
public int Height { get; } = height;
public Color Color {
get;
private set;
}
public bool IsTransparent {
get { return Color.A == 0 }
set { _isTransparent = value; }
}
public bool IsTransparent2 { get; } => Color.A == 0;
private bool _isTransparent;

// constructor
public Rectangle(int width, int height)
{
this.Width = width;
this.Height = height;
Color = Color.FromRgb(0, 255, 0);
}

// constructor with constructor chain
public Rectangle(int width, int height, Color color) : this(width, height)
{
this.Color = color;
}

// constructor with constructor chain to the constructor of the base class
public Rectangle(int width, int height, bool isTransparent) : base(width, height)
{
this.IsTransparent = isTransparent;
}

// deconstructor, called when the object is destroyed
public ~Rectangle()
{
Console.WriteLine("This object is destroyed");
}
}


public class Program
{
public static void Main(string[] args)
{
// create objects with call of the constructors
Rectangle rectangle1 = new Rectangle(10, 18);
Rectangle rectangle2 = new Rectangle(10, 18, Color.Green);
Rectangle rectangle3 = new Rectangle(10, 18, true);

// object initializer
Rectangle rectangle4 = new Rectangle(4, 9) { Color = Color.Yellow };
Rectangle rectangle5 = new Rectangle(12, 14)
{
Color = Color.Yellow,
            IsTransparent = true
};
}
}

Schlüsselwörter

Zugriffsmodifizierer und Sichtbarkeit

ZugrifssmodifiziererZugriffsraum
publicin der Solution
internalim Assembly
protectedin Klasse und Unterklassen (von Klasse ableitenden Klassen)
privatenur in Klasse

this und base

this

  • Verweis auf das aktuelle Objekt

  • Verwendung

    • Auflösung von Namenskonflikten

    • Übergabe des aktuellen Objektes an Methode

    • in Konstruktoren, um Klassenvariablen eindeutig zu identifizieren

    • Zugriff auf Klassenmitglieder (this ist optional)

base

  • Verweis auf die Oberklasse

Variablen

Instanzvariablen

  • sind eindeutig einer Instanz / einem Objekt zugeordnet
  • Gültigkeit auf Kontext dieser Instanz begrenzt
// Felder / Fields
public string str = "Hello";
protected double d = 1.2;
private int i = 10;
// internal: only in the same assembly accessable
internal string internalString = "";

Properties

public int Property { get; set; }
public int Property2 { get { return Property * 2; } private set; }
public string Property3 { get; private set; } => $"{str} {d}";

Klassenvariablen

  • gehören zur Klasse und nicht zu einem Objekt
  • mit static
public static int AnzahlAutos;

Datentypen

primitive Datentypen

  • speichern einfache, einzelne Werte
  • Zahlen, Buchstaben, Wahrheitswerte
  • in C#: int, double, char, bool, byte, …
  • im Stack gespeichert

Objekte

  • komplexere Gegenstände
  • können mehrere Eigenschaften und Verhaltensweisen haben
  • in C#: Instanzen von Klassen
    • Klasse = Bauanleitung des Aussehens und Verhaltens eines Objektes
  • Referenz im Stack, gespeichert im Heap

Wert- und Referenzübergabe

Wertübergabe - Call by Value

  • Übergabe einer Kopie des Wertes der Variable an Methode
  • keine Auswirkung der übergebenen Variable bei Änderung des Wertes
  • Standard bei primitiven Datentypen
  • sicherer, da unbeabsichtigte Änderungen an den Originalwerten verhindert werden

Referenzübergabe - Call by Reference

  • Übergabe eines Verweises auf ursprüngliche Variable an Methode
  • bei Änderung des Wertes in Methode wird auch ursprüngliche Variable verändert
  • Standard bei Objekten
  • mächtiger, da in Methode Wert von Objekten direkt verändert werden
  • kann zu unerwarteten Nebenwirkungen führen
// Reference type
void SetNumber(ref int val)
{
val = 2;
}

int i = 1;
SetNumber(ref i); // i => 2

void SetNumber(out int val)
{
val = 20;
}

i = 10;
SetNumber(out i); // i => 5
  • in C#
    • ref
      • übergibt Referenz auf Variable
      • muss nicht in Methode gesetzt werden
    • out
      • muss in Methode gesetzt werden

Methoden

Instanzmethoden

  • operieren auf den Instanzvariablen
public int Geschwindigkeit { get; private set; } = 0;

public void Beschleunige(int betrag)
{
Geschwindigkeit += betrag;
}

Klassenmethoden

  • arbeiten mit Klassenvariablen
  • können ohne Instanz der Klasse aufgerufen werden
public static void ZeigeAnzahlAutos()
{
Console.WriteLine($"Es gibt {AnzahlAutos} Autos.");
}

Methodensignatur

public int Addiere(int a, int b)
{
return a + b;
}
TeilBedeutung
publicZugriffsmodifizierer
intRückgabetyp
AddiereMethodenname
(int a, int b)Parameterliste
public int Addiere(int a, int b)
{
return a + b;
}
publicZugriffsmodifizierer
intRückgabetyp
AddiereMethodenname
int a, int bParameterliste

Methodenüberladung

  • Methoden mit gleichem Methodennamen
  • Rückgabetyp gehört nicht zur Methodensignatur bei Methodenüberladung
public int Addiere(int a, int b)
{
return a + b;
}

public double Addiere(double a, double b)
{
return a + b;
}

Konstruktoren und Destruktoren

Finalizer - C# | Microsoft Learn

Konstruktor

  • Bedeutung
    • Objekte werden mit Hilfe eines Konstruktors aus der Klasse (Vorlage) erstellt
    • spezielle Methode in Klasse, die bei Erstellung eines neuen Objektes aufgerufen wird
    • für die Initialisierung des Objektes
  • Anwendung
    • Setzen der Anfangswerte / Initialisierung eines neuen Objektes
public class Rectangle : Shape {
public int Width { get; }
public int Height { get; }
public Color Color { get; set; }
public bool IsTransparent { get; }

// constructor
public Rectangle(int width, int height)
{
this.Width = width;
this.Height = height;
}

// constructor with constructor chain to constructor of base class
public Rectangle(int width, int height, Color color) : base(width, height)
{
this.Color = color;
}

// constructor with constructor chain to constructor of this class
public Rectangle(int width, int height, bool isTransparent) : this(width, height)
{
this.IsTransparent = isTransparent;
}
}

public class Program
{
public static void Main(string[] args)
{
// use constructor
Rectangle rectangle1 = new Rectangle(10, 18);
Rectangle rectangle2 = new Rectangle(10, 18, Color.Green)
Rectangle rectangle3 = new Rectangle(10, 18, true);

// object initialiser
Rectangle rectangle4 = new Rectangle(4, 9) { Color = Color.Yellow };
Rectangle rectangle5 = new Rectangle(12, 14) { Color = Color.Yellow, IsTransparent = true };
}
}

verkürzter Konstruktor

public class Rectangle(int width, int height)
{
public int Width { get; } = width;
public int Height { get; } = height;
}

verkürzter Konstruktor mit Konstruktorenverkettung

public class Shape(int width, int height)
{
public int Width { get; } = width;
public int Height { get; } = height;
}

public class Rectangle(int width, int height) : Shape("Rectangle", width, height)
{
}

Destruktor

  • Bedeutung
    • Gegenteil eines Konstruktors
    • wird aufgerufen, wenn Objekt nicht mehr benötigt und Speicherplatz wieder freigegeben wird
    • räumt Objekt mit seinen Ressourcen auf
    • für die Freigabe von Ressourcen, die explizit verwaltet werden müssen
  • Anwendung
    • Aufräumen der Werte der Klasse bei Zerstörung des Objektes
public class Rectangle {
public int Width { get; }
public int Height { get; }
public Color Color { get; set; }
public bool IsTransparent { get; }

public Rectangle(int width, int height)
{
this.Width = width;
this.Height = height;
}


public Rectangle(int width, int height, Color color) : this(width, height)
{
this.Color = color;
}

public Rectangle(int width, int height, bool isTransparent) : this(width, height)
{
this.IsTransparent = isTransparent;
}

// deconstructor
public ~Rectangle()
{
Console.WriteLine("This object is destroyed");
}
}

Kontrollstrukturen

Selektion

int alter = 15;

if (alter >= 150)
{
Console.WriteLine("Du bist klinisch tot!"):
}
else if (alter >= 18)
{
Console.WriteLine("Du bist volljährig.");
}
else
{
Console.WriteLine("Du bist noch nicht volljährig.");
}

Iteration

Schlüsselwörter:

SchlüsselwortBedeutung
break;bricht Schleife ganz ab
continue;überspringt den Rest des Codes im jetzigen Durchgang und geht zum nächsten über

For-Schleife

for (int i = 0; i < 5; i++)
{
Console.WriteLine("Hallo! Dies ist die " + (i+1) + ". Runde.");
}

int[] numbers = { 2, 4, 6, 8, 10 };

for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] % 2 == 0)
{
Console.WriteLine($"{numbers[i]} ist eine gerade Zahl.");
}
}

While-Schleife

int zahl = 1;
while (zahl <= 10)
{
Console.WriteLine(zahl);
zahl++;
}

Foreach-Schleife

int[] zahlen = { 2, 4, 6, 8, 10 };

foreach (int zahl in zahlen)
{
if (zahl % 2 == 0)
{
Console.WriteLine($"{zahl} ist eine gerade Zahl.");
if (zahl < 0)
{
Console.WriteLine($"Die Schleife wird unterbrochen, weil die Zahl {zahl} negativ ist");
break;
}
}
}

Objekte

Arrays

  • feste Grösse nach der Deklarierung
  • direkter Zugriff auf Speicher/Daten über Indiz möglich

Eindimensionale Arrays

string[] notInitialized;
string[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
int[] myNum = {10, 20, 30, 40};

cars[0] = "Opel"; // set an element at an index
Console.WriteLine(cars[0]); // access to an element at an index

Console.WriteLine(cars.Length); // size of array

// reinitialization of the array
cars = new string[4];
cars = new string[4] {"Volvo", "BMW", "Ford", "Mazda"};
cars = new string[] {"Volvo", "BMW", "Ford", "Mazda"};

// will cause an error, keyword 'new' is required
cars = {"Volvo", "BMW", "Ford", "Mazda"}; // wrong !
cars = new {"Volvo", "BMW", "Ford", "Mazda"}; // correct

Mehrdimensionale Arrays

// initialization
int[,] numbers = {
// 0 1 2
{1, 4, 2}, // 0
{3, 6, 8} // 1
};

// access

Console.WriteLine(numbers[0, 2]); // -> 2
numbers[1, 0] = 7;

Listen

Generische Listen sind Listen, denen man bei der Erstellung mitteilen kann, aus welchem Datentyp sie bestehen.

  • Elemente können hinzugefügt und gelöscht werden

  • enthält viele Methoden

List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Clear();
bool b = list.Contains(1); // = false
b = list.Equals(new List<int>()); // = true

list.Add(1);
list.Add(2);
list.AddRange(new int[] { 3, 5 } );
list.Insert(3, 4); // -> 1, 2, 3, 4 5
list.Remove(4); // -> 1, 2, 3, 5
list.RemoveAt(2); // -> 1, 2, 5

list.Reverse(); // -> 5, 2, 1
list.Sort(); // -> 1, 2, 5

int count = list.Count // number of elements -> 3

Objektorientierte Programmierung

Vererbung

  • abgeleitete Klassen erben alle Eigenschaften und Methoden der Basisklassen und können eigene hinzufügen oder bestehende überschreiben
public class Person
{
public string Name { get; set; }

public Person(string name)
{
this.Name = name;
}
}

public class Kunde : Person
{
public int Umsatz { get; set; }

// a/this constructor is necessary
public Person(string name, int umsatz) : base(name)
{
this.Umsatz = umsatz;
}

// this constructor is possible too
public class Kunde(string name, int umsatz) : Person(name)
{
public int Umsatz { get; set; } = umsatz;
}
}

abstrakte Klassen

  • es können keine Instanzen von abstrakten Klassen erstellt werden
internal abstract class Person
{
public string Name { get; set; }
public string Vorname { get; set; }

public void Esse()
{
System.Console.WriteLine($"Ich bin {Vorname} {Name} und esse.");
}
}

internal class Kunde : Person
{
public int Umsatz { get; set; }

public void Kaufe()
{
System.Console.WriteLine("Ich kaufe.");
}
}

internal class Lagerist : Person
{
public int Groesse { get; set; }

public LagereEin()
{
System.Console.WriteLine("Ich lagere ein.");
}
}

abstrakte Methoden

mit Schlüsselwort abstract

  • müssen zwingend mit override überschrieben werden

mit Schlüsselwort virtual

  • dürfen optional mit override überschrieben werden

ohne Schlüsselwort

  • dürfen nicht überschrieben werden
  • können nur hinter neuen Methoden (mit Schlüsselwort new) "versteckt" werden, dies ist jedoch nicht Best Practice → Stack Overflow
public abstract class Person
{
public string Name { get; set; }
public string Vorname { get; set; }

// method may be overwritten
public **virtual** void Esse()
{
}

// method have to be overwritten
public **abstract** void Trage();
}

internal class Kunde : Person
{
public int Umsatz { get; set; }

public void Kaufe()
{
System.Console.WriteLine("Ich kaufe.");
}

// method have to be overwritten
public override Trage()
{
}
}

public class Kleinkind : Person
{
public int Alter { get; set; }

// method may be overwritten
public override void Esse()
{
}

// method have to be overwritten
public override void Trage()
{
}
}

Interface

  • Schnittstelle
    • keine Implementierung der Methoden → enthält nur Methodensignaturen
    • keine Instanzierung möglich
    • definiert Methoden, die Klasse überschreiben muss
    • public nicht notwendig, Methoden sind automatisch public
  • Implementierung von einer Klasse
    • gleich wie die Implementierung einer abstrakten Klasse
    • Methoden müssen nicht mit override überschrieben werden - sie werden nur fertig deklariert
public interface IKannFliegen
{
void Fliegen();
}

public class Vogel : IKannFliegen
{
// without override
public Fliegen()
{
System.Console.WriteLine("Ich fliege ...");
}
}

Enumeration

  • Aufzählungstyp
enum Status
{
NotStarted,
InProgress,
Done
}
enum Status
{
NotStarted,
InProgress,
Done;

private string _text;

Status(string text)
{
this._text = text;
}

public string Print()
{
Console.WriteLine(_text);
return _text;
}
}

Testing

Unittests

Mit Unittests kann Code