Skip to content

Commit 9dda709

Browse files
committed
Revise L16
1 parent c017e1b commit 9dda709

1 file changed

Lines changed: 42 additions & 25 deletions

File tree

16_Generics.md

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
author: Sebastian Zug, Galina Rudolf & André Dietrich
44
email: sebastian.zug@informatik.tu-freiberg.de
5-
version: 1.0.5
5+
version: 1.0.6
66
language: de
77
narrator: Deutsch Female
88
comment: Generische Typen und Methoden, Constrains und Vererbung bei generischen Typen
@@ -35,8 +35,7 @@ import: https://raw.githubusercontent.com/TUBAF-IfI-LiaScript/VL_Softwareentwick
3535

3636
## Nachgefragt und nachgedacht
3737

38-
+ Beispiel zur Anwendung der Polymorphie
39-
+ Interfaces
38+
> **Frage:** Was ist der Unterschied zwischen einem Interface und einer abstrakten Klasse?
4039
4140
| interface | abstract class |
4241
| --------------------------------- | ------------------------------------------------- |
@@ -48,7 +47,7 @@ import: https://raw.githubusercontent.com/TUBAF-IfI-LiaScript/VL_Softwareentwick
4847
| keine statischen Member | statische Member möglich |
4948

5049

51-
```
50+
```csharp InterfaceVsAbstractClass
5251
interface IFile
5352
{
5453
void ReadFile();
@@ -119,7 +118,7 @@ public class Program{
119118
```
120119
@LIA.eval(`["main.cs"]`, `mcs main.cs`, `mono main.exe`)
121120

122-
Die Dokumentation von `Array` findet sich unter https://docs.microsoft.com/de-de/dotnet/api/system.array?view=netcore-3.1
121+
Die Dokumentation von `Array` findet sich unter https://learn.microsoft.com/de-de/dotnet/api/system.array?view=net-9.0
123122

124123
> **Merke:** Arrays sind in C# statisch definiert und haben keine veränderliche Größe.
125124

@@ -136,6 +135,9 @@ Lassen Sie uns einen alternativen Ansatz bestreiten. Wir implementieren ein eige
136135

137136
```
138137

138+
> [!CAUTION]
139+
> Die nachfolgende Implementierung soll beispielhaft die Umsetzung einer verketteten Liste zeigen - es handelt sich um eine rudimentäre Umsetzung. Benutzen Sie für die Praxis die entsprechenden .NET-Bibliotheken, z.B. `LinkedList<T>` aus `System.Collections.Generic`!
140+
139141
```csharp LinkedList.cs
140142
using System;
141143

@@ -173,7 +175,7 @@ public class LinkedList{
173175
current = current.next;
174176
count++;
175177
}
176-
return 1;
178+
throw new IndexOutOfRangeException();
177179
}
178180
}
179181
}
@@ -204,10 +206,8 @@ Boxing und Unboxing würden die spezifischen Datentypen auf diesen abgebildet.
204206

205207
```csharp
206208
int i = 123;
207-
object o = i; // The following line boxes i.
208-
209-
o = 123;
210-
i = (int)o; // unboxing
209+
object o = i; // boxing: der Werttyp i wird auf den Heap kopiert
210+
int j = (int)o; // unboxing: explizite Cast-Operation erforderlich
211211
```
212212

213213
Nachteilig daran ist, dass
@@ -293,7 +293,8 @@ class MyGenericClass<T, U>
293293
}
294294
```
295295

296-
Hinsichtlich der Namenswahl für die generischen Typen sind sie frei, sollten aber berücksichtigen, dass für den Leser ggf. unklar ist, wie welcher konkrete Datentyp realisiert werden kann. Die Einbuchstabenvariante "T" sollte nur genutzt werden, wenn in Bezug auf einen Container die Bedeutung wirklich klar ist.
296+
> [!CAUTION]
297+
> Hinsichtlich der Namenswahl für die generischen Typen sind sie frei, sollten aber berücksichtigen, dass für den Leser ggf. unklar ist, wie welcher konkrete Datentyp realisiert werden kann. Die Einbuchstabenvariante "T" sollte nur genutzt werden, wenn in Bezug auf einen Container die Bedeutung wirklich klar ist.
297298

298299
```csharp StackExample
299300
using System;
@@ -312,7 +313,7 @@ public class Stack<T>{
312313
}
313314

314315
public T Pop(){
315-
return data[position--];
316+
return data[--position];
316317
}
317318

318319
public override string ToString(){
@@ -445,7 +446,7 @@ anderen Namen.
445446

446447
Verwenden Sie Beschränkungen, analog zu den generischen Typen, sinnvolle Einschränkungen für die Typparametern in Methoden gewährleisten. Das folgende Beispiel gibt als Beschränkung die Implementierung des Interfaces IComparable<T> an, um unseren Vergleich zu realisieren.
447448

448-
```csharp IComparable
449+
```csharp SwapIfGreater
449450
using System;
450451

451452
public class Program{
@@ -476,7 +477,7 @@ Interface implementieren, existieren müssen.
476477

477478
https://learn.microsoft.com/de-de/dotnet/api/system.icomparable?view=net-9.0
478479

479-
```csharp IComparable
480+
```csharp IComparableImplementierung
480481
using System;
481482

482483
public class Animal : IComparable<Animal> {
@@ -541,7 +542,7 @@ public class Program{
541542
Wie bereits bei den generischen Methoden angedeutet können wir mittels "Beschränkungen" sicherstellen, dass eine gültige Operation für einen Datentyp existiert.
542543

543544

544-
```csharp initKeyword
545+
```csharp PlusOhneConstraint
545546
using System;
546547

547548
public class Program{
@@ -561,8 +562,7 @@ public class Program{
561562
<Project Sdk="Microsoft.NET.Sdk">
562563
<PropertyGroup>
563564
<OutputType>Exe</OutputType>
564-
<TargetFramework>net6.0</TargetFramework>
565-
<EnablePreviewFeatures>true</EnablePreviewFeatures>
565+
<TargetFramework>net8.0</TargetFramework>
566566
</PropertyGroup>
567567
</Project>
568568
```
@@ -571,14 +571,31 @@ public class Program{
571571
Folglich ist es notwendig die Allgemeinheit der generischen Methoden oder Klassen zu
572572
beschränken. Man definiert Beschänkungen oder *Constraints*, die die Breite der verwendbaren Datentypen einschränken. Die Typprüfung bezieht diese Informationen dann ein.
573573

574-
| Beschränkung | Das Typargument muss ... |
575-
| --------------------------- | ------------------------------------------------------- |
576-
| `where T : struct` | ... ein Werttyp sein. |
577-
| `where T : class` | ... ein Verweistyp sein. |
578-
| `where T : <Basisklasse>` | ... die Basisklasse sein oder von ihr abgeleitete sein. |
579-
| `where T : <Schnittstelle>` | ... die Schnittstelle sein oder diese implementieren. |
574+
| Beschränkung | Das Typargument muss ... |
575+
| --------------------------- | ----------------------------------------------------------------- |
576+
| `where T : struct` | ... ein Werttyp (Nicht-Nullable) sein. |
577+
| `where T : class` | ... ein Verweistyp sein. |
578+
| `where T : notnull` | ... ein Nicht-Nullable-Typ (Wert- oder Verweistyp) sein. |
579+
| `where T : unmanaged` | ... ein _unmanaged_ Werttyp sein (keine Referenzen enthalten). |
580+
| `where T : new()` | ... einen öffentlichen, parameterlosen Konstruktor besitzen. |
581+
| `where T : <Basisklasse>` | ... die Basisklasse sein oder von ihr abgeleitet sein. |
582+
| `where T : <Schnittstelle>` | ... die Schnittstelle sein oder diese implementieren. |
583+
584+
Mehrere Beschränkungen lassen sich kombinieren; dabei gilt eine feste Reihenfolge: zuerst `struct`/`class`/`notnull`, dann Basisklasse und Schnittstellen, zuletzt `new()`.
585+
586+
```csharp
587+
class EmployeeList<T> where T : notnull, Employee, IComparable<T>, new() { }
588+
```
580589

581-
> Unter `net7` lässt sich obiges Problem sehr elegant mit einem `where T : INumber<T>` lösen. Testen Sie dieses Feature auf Ihrem lokalen Rechner. [Link](https://devblogs.microsoft.com/dotnet/dotnet-7-generic-math/)
590+
> Obiges Problem lässt sich sehr elegant über die Beschränkung `where T : INumber<T>` lösen. Das Interface `INumber<T>` (aus `System.Numerics`) fasst die arithmetischen Operatoren als `static abstract`-Member zusammen, sodass `+`, `-` usw. innerhalb der generischen Methode garantiert verfügbar sind.
591+
>
592+
> ```csharp
593+
> using System.Numerics;
594+
>
595+
> static T Plus<T>(T x, T y) where T : INumber<T> {
596+
> return x + y; // dank Constraint nun gültig
597+
> }
598+
> ```
582599

583600
Das folgende Beispiel setzt die Möglichkeiten der Beschränkung konsequent um und lässt nur Klasse
584601
`Employee` zu. Damit wird sichergestellt, dass die Methoden,
@@ -615,7 +632,7 @@ ggf. notwendig die spezifischen Parameter des Datentyps zur Laufzeit
615632
auszuwerten. Im folgenden sollen die Beispiele die Bedeutung diese Vorgehens
616633
aufzeigen.
617634

618-
```csharp IComparable
635+
```csharp ReflectionConstraints
619636
using System;
620637
using System.Reflection;
621638

0 commit comments

Comments
 (0)