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
Zugrifssmodifizierer | Zugriffsraum |
---|---|
public | in der Solution |
internal | im Assembly |
protected | in Klasse und Unterklassen (von Klasse ableitenden Klassen) |
private | nur 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
- ref
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;
}
Teil | Bedeutung |
---|---|
public | Zugriffsmodifizierer |
int | Rückgabetyp |
Addiere | Methodenname |
(int a, int b) | Parameterliste |
public int Addiere(int a, int b)
{
return a + b;
}
public | Zugriffsmodifizierer |
---|---|
int | Rückgabetyp |
Addiere | Methodenname |
int a, int b | Parameterliste |
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üsselwort | Bedeutung |
---|---|
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 automatischpublic
- 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