Skip to content

Commit b2dd46c

Browse files
committed
Revise Project of the Week L07
1 parent 7a1dab8 commit b2dd46c

3 files changed

Lines changed: 133 additions & 48 deletions

File tree

07_OOPGrundlagenI.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,130 @@ public class Program
645645
646646
> **Vertiefung:** Vorlesung 08 zeigt **Properties** als idiomatische C#-Lösung für „kontrollierter Zugriff auf private Felder" (statt expliziter Getter/Setter wie in 07a). Vorlesung 09 erklärt `protected` und die Wechselwirkungen mit Vererbung.
647647
648+
## Beispiel: `internal` in Aktion
649+
650+
`public` und `private` sind in einem einzigen `.cs`-File leicht zu sehen. `internal` braucht eine **zweite Assembly**, damit der Effekt überhaupt sichtbar wird — innerhalb *einer* Assembly verhält sich `internal` wie `public`. Dazu steigen wir kurz in ein echtes Mini-Projekt unter [`code/08_OOP/assemblies_dotnet/`](code/08_OOP/assemblies_dotnet/) ein.
651+
652+
```ascii
653+
assemblies_dotnet/
654+
655+
├── assemblies_dotnet.slnx <- Solution: Klammer um beide Projekte (XML, ab .NET 9)
656+
657+
├── MyApp/ <- Projekt 1: ausführbar
658+
│ ├── MyApp.csproj (OutputType = Exe, ProjectReference -> MyClass)
659+
│ └── Program.cs
660+
661+
└── MyClass/ <- Projekt 2: Bibliothek
662+
├── MyClass.csproj (kein OutputType -> Default: Library)
663+
└── Farmland.cs
664+
665+
Nach 'dotnet build' entstehen:
666+
MyClass/bin/Debug/net9.0/MyClass.dll <- Assembly 1
667+
MyApp/bin/Debug/net9.0/MyApp.dll <- Assembly 2 (lädt MyClass.dll)
668+
```
669+
670+
| Begriff | Was es ist | Wofür |
671+
| ------------- | ----------------------------------------- | ---------------------------------------------------------- |
672+
| **Solution** (`.slnx`) | Verwaltungs-Container für mehrere Projekte | nur Tooling-Hilfe, baut selbst nichts. Klassisches Format `.sln` ist im Industrieumfeld noch verbreitet, das schlankere XML-Format `.slnx` ist seit .NET 9 verfügbar |
673+
| **Projekt** (`.csproj`) | Beschreibung, was kompiliert wird | erzeugt jeweils **eine** Assembly |
674+
| **Assembly** (`.dll`/`.exe`) | physische Build-Ausgabe | Deployment-Einheit + Sichtbarkeitsgrenze für `internal` |
675+
676+
> **Häufige Verwechslung — bitte einmal explizit klarstellen:**
677+
>
678+
> | Achse | Wer steuert? | Sichtbarkeit |
679+
> | ------------ | ----------------------- | --------------------------------------------- |
680+
> | **Namespace** | `namespace Farm { ... }` | logischer Name, hat *nichts* mit Sichtbarkeit zu tun |
681+
> | **Assembly** | `.csproj` / Build | physische Grenze; `internal` operiert *hier* |
682+
>
683+
> `using Farm;` erlaubt den **Namespace**-Zugriff. `<ProjectReference>` erlaubt den **Assembly**-Zugriff. Beide sind unabhängig.
684+
685+
### Inhaltlicher Aufbau des Beispiels
686+
687+
In `MyClass/Farmland.cs` liegen zwei Typen mit unterschiedlicher Sichtbarkeit:
688+
689+
```csharp
690+
namespace Farm
691+
{
692+
internal struct Animal // <- nur in MyClass.dll sichtbar
693+
{
694+
public string name;
695+
public string sound;
696+
697+
public Animal(string name, string sound = "Miau") { ... }
698+
public override string ToString() => $"Mein Name ist {name}, {sound}!";
699+
}
700+
701+
public class FarmFacade // <- öffentliche Schnittstelle
702+
{
703+
private List<Animal> animals = new();
704+
705+
public void Register(string name, string sound = "Miau") { ... } // legt Animal an
706+
public string MorningCall() { ... } // gibt Text zurück
707+
}
708+
}
709+
```
710+
711+
`FarmFacade` *darf* `Animal` benutzen, weil beide zur selben Assembly gehören. Von außen — etwa aus `MyApp.dll` — ist nur `FarmFacade` sichtbar; `Animal` bleibt unsichtbar, obwohl der Quellcode in derselben Repository-Datei offen lesbar steht.
712+
713+
> **Beachten Sie das Fassaden-Muster:** `MorningCall()` gibt nur einen `string` zurück, also einen Standardtyp. Der interne `Animal`-Typ überquert die Assembly-Grenze nie. Das ist *die* idiomatische Verwendung von `internal`.
714+
715+
### Drei Schritte, die Sie selbst ausprobieren
716+
717+
**Schritt 1 — bauen und ausführen:**
718+
719+
```bash
720+
cd code/08_OOP/assemblies_dotnet
721+
dotnet build # baut MyClass.dll, dann MyApp.dll
722+
dotnet run --project MyApp
723+
```
724+
725+
Erwartete Ausgabe:
726+
727+
```
728+
Mein Name ist Kitty, Miau!
729+
Mein Name ist Wally, Wuff!
730+
Mein Name ist Berta, Muuh!
731+
```
732+
733+
Die App ruft `FarmFacade` auf, registriert drei Tiere und holt sich den `MorningCall`-Text. Das funktioniert — `FarmFacade` ist `public`.
734+
735+
**Schritt 2 — den verbotenen Zugriff sehen:**
736+
737+
In `MyApp/Program.cs` ist im `Main` ein Experimentier-Block enthalten. Entfernen Sie die führenden `//` vor der Animal-Zeile:
738+
739+
```csharp
740+
var cat = new Animal("Kitty");
741+
```
742+
743+
`dotnet build` liefert:
744+
745+
```
746+
error CS0122: 'Farm.Animal' is inaccessible due to its protection level
747+
```
748+
749+
Der Compiler **sieht** den Typ `Animal` (er steht ja im Quellcode der referenzierten DLL), erlaubt aber den Zugriff nicht — `internal` blockt über die Assembly-Grenze hinweg.
750+
751+
**Schritt 3 — die Grenze öffnen:**
752+
753+
In `MyClass/Farmland.cs` das `internal` durch `public` ersetzen:
754+
755+
```csharp
756+
public struct Animal { ... }
757+
```
758+
759+
`dotnet build` läuft wieder durch. Genau dieser Toggle macht den Unterschied erfahrbar: Eine Bibliothek entscheidet, *was* sie nach außen anbietet — und versteckt den Rest.
760+
761+
### Was Sie aus dem Beispiel mitnehmen sollten
762+
763+
| Erkenntnis | Warum es wichtig ist |
764+
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
765+
| Ein .NET-Programm kann aus mehreren Projekten und Assemblies bestehen | Realität jenseits der „eine `Main`-Datei"-Vorlesungssicht |
766+
| `internal` operiert auf **Assembly-Grenze**, nicht auf Namespace-Grenze | Häufigste Verwechslung — einmal richtig verstehen |
767+
| **Öffentliche Fassade + interne Implementierung** ist *das* Standardmuster für Bibliotheken | Genau dafür existiert `internal` |
768+
| `dotnet build` erkennt Abhängigkeitsreihenfolge und baut nur, was sich geändert hat | Modulare Builds = schnellere Iteration |
769+
770+
> **Vertiefung in 08:** Wir schauen uns dort an, wie diese Struktur per `dotnet new sln` / `dotnet new console` / `dotnet new classlib` / `dotnet add reference` von Hand erzeugt wird — und warum NuGet-Pakete im Kern dasselbe Konzept sind, nur mit zusätzlicher Distribution.
771+
648772
## Aufgaben
649773

650774
1. **Übersetzen.** Übertragen Sie das `Animal`-Beispiel aus 07a (mit `make_noise`) nach C#. Erzeugen Sie drei Instanzen und rufen Sie `MakeNoise()` in einer Schleife auf.

code/08_OOP/assemblies_dotnet/assemblies_dotnet.sln

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Solution>
2+
<Configurations>
3+
<Platform Name="Any CPU" />
4+
<Platform Name="x64" />
5+
<Platform Name="x86" />
6+
</Configurations>
7+
<Project Path="MyApp/MyApp.csproj" />
8+
<Project Path="MyClass/MyClass.csproj" />
9+
</Solution>

0 commit comments

Comments
 (0)