Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
53m 20s
Design Patterns in C# sind wichtige Werkzeuge für das Schreiben von effizientem, wiederverwendbarem und wartbarem Code. Diese Muster bieten Standardlösungen für gängige Software-Design-Probleme, fördern Best Practices und helfen Entwicklern, redundanten Code zu vermeiden. Eines der wichtigsten Prinzipien bei der Anwendung von Entwurfsmustern ist das DRY-Prinzip (Don't Repeat Yourself), das die Minimierung von Wiederholungen im Code betont, um die Lesbarkeit und Wartbarkeit zu verbessern.
Dieser Artikel ist inspiriert von Tim Coreys aufschlussreichem Video "Design Patterns: Don't Repeat Yourself in C#", das tief in das DRY-Prinzip und seine praktische Anwendung bei der Erstellung von sauberem, besser organisiertem Code eintaucht. Durch die Untersuchung der Schlüsselkonzepte und -strategien, die in Tims Video besprochen werden, soll dieser Artikel Ihnen einen umfassenden Leitfaden zur effektiven Umsetzung des DRY-Entwurfsmusterprinzips in Ihren C#-Projekten an die Hand geben.
In der Einleitung erklärt Tim Corey das DRY-Prinzip, das für "Don't Repeat Yourself" steht Dieses Prinzip ist ein grundlegendes Konzept in der Programmierung, das darauf abzielt, Redundanzen zu vermeiden, indem sichergestellt wird, dass jedes Wissen oder jede Logik an einer einzigen Stelle im Code dargestellt wird. Tim veranschaulicht das Prinzip anhand eines einfachen Beispiels für eine WinForms-Anwendung mit einem Dashboard-Formular. Das Formular enthält Felder für die Eingabe eines Vor- und Nachnamens sowie eine Schaltfläche zur Generierung einer Mitarbeiter-ID auf der Grundlage dieser Felder.
Bei (0:53) geht Tim dazu über, Wiederholungen im Code zu erkennen und zu antizipieren. Am Beispiel der WinForms-Anwendung zeigt er, wie Wiederholungen auftreten können, auch wenn Methoden nur einmal aufgerufen werden. In der Anwendung umfasst die Logik zur Erzeugung von Mitarbeiter-IDs das Extrahieren von Teilzeichenfolgen aus den Textfeldern für die Vor- und Nachnamen und das Anhängen eines 3-stelligen Codes am Ende.

Im obigen Screenshot (1:31) demonstriert Tim die Funktionalität der Anwendung, indem er zeigt, wie eine Mitarbeiter-ID durch die Kombination der ersten vier Buchstaben des Vor- und Nachnamens mit einem dreistelligen Code erzeugt wird. Er hebt hervor, dass der Code zwar dem DRY-Prinzip zu folgen scheint, da er dieselbe Logik nicht explizit wiederholt, dass es jedoch grundlegende Probleme mit dem Wiederholungsmuster gibt, die behoben werden müssen.
Bei (1:51) weist er darauf hin, dass der Code zwar einfach erscheint, aber nicht vollständig dem DRY-Prinzip entspricht, da die Logik zur Generierung der Mitarbeiter-ID eng mit dem Klick-Ereignis der Schaltfläche gekoppelt ist. Das bedeutet, dass der Code wiederholt oder angepasst werden müsste, wenn diese Logik an anderer Stelle im Client-Code benötigt würde, z. B. bei der Verarbeitung einer Liste neuer Mitarbeiter (3:58), was zu Redundanz führen würde.
In diesem Segment demonstriert Tim Corey, wie man eine unabhängige, wiederverwendbare Methode erstellt, um das DRY-Prinzip einzuhalten. Er beginnt damit, die Logik zur Generierung einer Mitarbeiter-ID aus dem Event-Handler in eine separate Methode zu extrahieren. Diese Umstrukturierung beinhaltet das Erstellen einer privaten Methode namens GenerateEmployeeID und das Verschieben des vorhandenen Codes in diese Methode (5:15). Der überarbeitete Code im Event-Handler ruft dann einfach diese Methode auf.
Anfangscode: Die Logik für die Generierung der Mitarbeiter-ID befand sich direkt im Click-Event-Handler einer Schaltfläche.

Refactored Code: Tim verbessert die Methode, indem er sie flexibler macht. Anstatt sich auf bestimmte UI-Elemente zu verlassen, akzeptiert die Methode jetzt firstName und lastName als Parameter und gibt die generierte ID zurück. Durch diese Änderung kann die Methode in verschiedenen Kontexten und UI-Elementen verwendet werden:
private string GenerateEmployeeID(string firstName, string lastName)
{
string employeeID = firstName.Substring(0, 4) + lastName.Substring(0, 4) + DateTime.Now.Millisecond.ToString();
return employeeID;
}
Anschließend demonstriert Tim, wie diese Methode über das Klick-Ereignis aufgerufen wird:
employeeIdText.Text = GenerateEmployeeID(firstNameText.Text, lastNameText.Text);employeeIdText.Text = GenerateEmployeeID(firstNameText.Text, lastNameText.Text)Er weist auch darauf hin, dass diese Methode nun auch in anderen Teilen der Anwendung verwendet werden kann, z. B. bei der Verarbeitung von CSV-Dateien mit mehreren Mitarbeiterdatensätzen, ohne den Code zu wiederholen.
Tim Corey erforscht dann das Konzept einer Klassenbibliothek, um die Wiederverwendung von Code und die Wartbarkeit zu verbessern. Er veranschaulicht, wie die GenerateEmployeeID Methode in ein Klassenbibliotheksobjekt gekapselt wird, das in mehreren Projekten verwendet werden kann.
Bei (8:00) erklärt Tim, dass sich das Design immer wieder ändert, je nach den Anforderungen der Benutzer oder den Unternehmensrichtlinien, um es mit Grafiken und Animationen interaktiver zu gestalten. Also stellt er ein WPF-Projekt innerhalb der Lösung mit genauen Feldern und einer Schaltfläche zum Generieren einer Mitarbeiter-ID vor.
Tim (9:15) plädiert nachdrücklich für die Verwendung einer Klassenbibliothek, indem er sagt, dass der Code in das neue WPF-Projekt kopiert worden wäre, wenn wir uns nicht wiederholen wollten. Um das Ganze DRY zu halten, müssen wir also Klassen in einer Klassenbibliothek erstellen.
Erstellung der Klassenbibliothek:
Tim (9:47) erstellt ein neues Klassenbibliotheksprojekt in .NET Framework und benennt es DRYDemoLibrary.
In dieser Bibliothek definiert er eine öffentliche Klasse EmployeeProcessor und verschiebt die GenerateEmployeeID Methode in diese Klasse:
public class EmployeeProcessor
{
public string GenerateEmployeeID(string firstName, string lastName)
{
string employeeID = firstName.Substring(0, 4) + lastName.Substring(0, 4) + DateTime.Now.Millisecond.ToString();
return employeeID;
}
}
Verwendung der Klassenbibliothek in Projekten:
In seinen WinForms- (13:18) und WPF-Projekten (14:00) fügt Tim einen Verweis auf die Klassenbibliothek DRYDemoLibrary hinzu.
Er ersetzt dann den alten Code durch Aufrufe der GenerateEmployeeID Methode aus der Klassenbibliothek:
EmployeeProcessor processor = new EmployeeProcessor();
employeeIDText.Text = processor.GenerateEmployeeID(firstNameText.Text, lastNameText.Text);
Durch diesen Ansatz wird Redundanz vermieden, da die Methode nun an einer einzigen Stelle gepflegt wird. Tim zeigt, dass dieselbe Klassenbibliothek in verschiedenen UI-Frameworks (WinForms und WPF) verwendet werden kann, ohne den Code zu wiederholen.
Vorteile:
Konsistenz: Durch die Zentralisierung der Logik in einer Klassenbibliothek stellt Tim sicher, dass Änderungen an der Logik (z. B. Fehlerbehebungen) in allen Projekten einheitlich angewendet werden.
Reduzierte Wartung: Änderungen an der Methode müssen nur in der Klassenbibliothek vorgenommen werden, um Inkonsistenzen zu vermeiden und den Wartungsaufwand zu verringern.
Tim Corey erforscht weiterhin, wie die DRYDemoLibrary-Klassenbibliothek in verschiedenen Projekttypen verwendet werden kann, wobei er sich insbesondere auf die Integration der Bibliothek in eine neue Konsolenanwendung konzentriert. Dies zeigt, wie die Funktionalität der Bibliothek in verschiedenen Anwendungen wiederverwendet werden kann, nicht nur in einer einzigen Instanz oder nur innerhalb derselben Lösung.
Erstellung einer neuen Lösung und eines neuen Projekts:
Tim (17:29) beginnt mit der Erstellung einer neuen Lösung für eine Konsolenanwendung und simuliert ein Szenario, in dem Sie die DRYDemoLibrary in einer anderen Art von Projekt, wie einem Windows-Dienst oder einer Konsolenanwendung, verwenden müssen.
Er nennt das neue Projekt ConsoleUI und zeigt, wie man eine einfache Konsolenanwendung einrichtet.
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
Hinzufügen einer Referenz zur Klassenbibliothek:
Tim erklärt, wie man einen Verweis auf die DRYDemoLibrary DLL in das neue Projekt einfügt. Dazu muss die DLL-Datei im bin-Ordner des Klassenbibliotheksprojekts aufgerufen und der Konsolenanwendung hinzugefügt werden.
using DRYDemoLibrary;Imports DRYDemoLibrarySobald die Referenz hinzugefügt ist, verwendet Tim (19:24) die EmployeeProcessor-Klasse aus der Bibliothek, um eine Mitarbeiter-ID auf der Grundlage von Benutzereingaben zu generieren.
Console.WriteLine("What is your first name?");
string firstName = Console.ReadLine();
Console.WriteLine("What is your last name?");
string lastName = Console.ReadLine();
EmployeeProcessor processor = new EmployeeProcessor();
string employeeID = processor.GenerateEmployeeID(firstName, lastName);
Console.WriteLine($"Your employee ID is {employeeID}");
Ausführen der Konsolenanwendung:
Tim demonstriert, wie die Konsolenanwendung ausgeführt wird, um zu zeigen, dass die Mitarbeiter-ID mithilfe der Bibliothek erfolgreich generiert wird. Dies bestätigt, dass derselbe Code aus der Klassenbibliothek in verschiedenen Projekten wiederverwendet werden kann.

Aktualisierung der DLL:
Tim Corey führt kurz in das Konzept der Verwendung von NuGet-Paketen für die Verwaltung und Aktualisierung von Klassenbibliotheken ein. Dieser Ansatz bietet eine besser skalierbare Lösung für die Handhabung von Abhängigkeiten und Aktualisierungen, insbesondere in größeren Projekten oder Organisationen.
Erstellen eines NuGet-Pakets:
Aktualisierung der Pakete:
Vorteile:
Zentrale Verwaltung: NuGet-Pakete bieten eine zentrale Möglichkeit, Bibliotheksversionen und Abhängigkeiten zu verwalten.
Einfache Updates: Die Aktualisierung der Bibliothek über mehrere Projekte hinweg wird einfacher und zuverlässiger.
Integration: NuGet lässt sich in verschiedene Entwicklungstools und -umgebungen integrieren, wodurch die Verwaltung von Bibliotheksabhängigkeiten vereinfacht wird.
In diesem Segment demonstriert Tim Corey, wie die Anwendung des DRY-Prinzips (Don't Repeat Yourself) Unit-Tests verbessern kann. Er zeigt, wie DRY-Prinzipien in der Entwicklungsarbeit umgesetzt werden können, wobei er sich besonders auf Unit-Tests konzentriert.
Tim beginnt mit der Ausführung eines Unit-Tests, der aufgrund eines Fehlers in der DLL fehlschlägt. Er hebt die Bedeutung von Unit-Tests bei der Identifizierung von Problemen hervor, selbst wenn der Code außerhalb der Hauptlösung liegt. Der Code erwartete eine Eingabe mit 4 Buchstaben, stattdessen übergab Tim einen Vornamen mit 3 Buchstaben, der in der DLL-Datei abstürzt, auch wenn er nicht direkt in der Lösung enthalten ist.

Um das Problem mit der Behandlung von Vornamen zu lösen, überarbeitet Tim den Code. Er erklärt, wie DRY auf die Entwicklung angewendet werden kann, indem er ein neues Klassenbibliotheksprojekt erstellt (23:50). Dieser Ansatz stellt sicher, dass Änderungen an mehreren Objekten einmal vorgenommen und effektiv getestet werden können, ohne dass sich die Korrekturen wiederholen.

Tim führt eine neue Testklasse als EmployeeProcessorTest in das Klassenbibliotheksprojekt ein und richtet Unit-Tests mit XUnit ein. Er demonstriert, wie eine Testmethode zur Generierung von Mitarbeiter-IDs erstellt wird, und erörtert die Bedeutung von Mocking-Abhängigkeiten, anstatt sich auf tatsächliche Werte zu verlassen.

Tim schreibt eine Unit-Test-Methode namens GenerateEmployeeID_ShouldCalculate. Er stellt eine Theorie mit Inline-Daten auf, um verschiedene Szenarien zu testen und sicherzustellen, dass die Methode die erwarteten Ergebnisse liefert. Er erklärt auch, wie man Assert.Equal verwendet, um die Ausgabe zu überprüfen.
public class EmployeeProcessorTest
{
[Theory]
[InlineData("Timothy", "Corey", "TimoCore")]
public void GenerateEmployeeID_ShouldCalculate(string firstName, string lastName, string expectedStart)
{
// Arrange
var processor = new EmployeeProcessor();
// Act
var actualStart = processor.GenerateEmployeeID(firstName, lastName).Substring(0, 8);
// Assert
Assert.Equal(expectedStart, actualStart);
}
}Public Class EmployeeProcessorTest
<Theory>
<InlineData("Timothy", "Corey", "TimoCore")>
Public Sub GenerateEmployeeID_ShouldCalculate(firstName As String, lastName As String, expectedStart As String)
' Arrange
Dim processor = New EmployeeProcessor()
' Act
Dim actualStart = processor.GenerateEmployeeID(firstName, lastName).Substring(0, 8)
' Assert
Assert.Equal(expectedStart, actualStart)
End Sub
End ClassTim betont die Bedeutung des Mockings dynamischer Daten, wie z. B. Datums- und Zeitwerte, zur Kontrolle von Testbedingungen und -ergebnissen. Er erörtert die Herausforderung der Arbeit mit dynamischen Zeichenketten und wie man verschiedene Szenarien mit kontrollierten Werten testen kann. Er führt dann den Komponententest aus, fügt jedoch zuvor zwei NuGet-Pakete hinzu, die zum Ausführen der Tests erforderlich sind: xunit.runner.console und xunit.runner.visualstudio.

Nachdem alle Tests für eine Inline-Datei erfolgreich durchgeführt wurden, wird die Ausgabe wie folgt angezeigt:

Jetzt, bei (31:30), fügte Tim weitere Inline-Daten hinzu und änderte den zweiten Parameter des Unterstrings zu expectedStart.Length:
public class EmployeeProcessorTest
{
[Theory]
[InlineData("Timothy", "Corey", "TimoCore")]
[InlineData("Tim", "Corey", "TimCore")]
public void GenerateEmployeeID_ShouldCalculate(string firstName, string lastName, string expectedStart)
{
var processor = new EmployeeProcessor();
var actualStart = processor.GenerateEmployeeID(firstName, lastName).Substring(0, expectedStart.Length);
Assert.Equal(expectedStart, actualStart);
}
}Public Class EmployeeProcessorTest
<Theory>
<InlineData("Timothy", "Corey", "TimoCore")>
<InlineData("Tim", "Corey", "TimCore")>
Public Sub GenerateEmployeeID_ShouldCalculate(firstName As String, lastName As String, expectedStart As String)
Dim processor = New EmployeeProcessor()
Dim actualStart = processor.GenerateEmployeeID(firstName, lastName).Substring(0, expectedStart.Length)
Assert.Equal(expectedStart, actualStart)
End Sub
End ClassNach der erneuten Ausführung des Einheitstests bei (32:05) brach der Test bei der zweiten Theorie ab:

Um dem DRY-Prinzip zu folgen, strukturiert Tim den Code weiter um, indem er eine private Methode GetPartOfName in der aktuellen EmployeeProcessor Klasse unter DRYDemoLibrary erstellt. Mit dieser Methode können Teile eines Namens extrahiert werden, was die Wiederverwendbarkeit und Lesbarkeit des Codes verbessert. Tim hat die folgenden Änderungen vorgenommen:
public string GenerateEmployeeID(string firstName, string lastName)
{
string employeeID = $@"{GetPartOfName(firstName, 4)}{GetPartOfName(lastName, 4)}{DateTime.Now.Millisecond.ToString()}";
return employeeID;
}
private string GetPartOfName(string name, int numberOfCharacters)
{
string output = name;
if (name.Length > numberOfCharacters)
{
output = name.Substring(0, numberOfCharacters);
}
return output;
}Public Function GenerateEmployeeID(ByVal firstName As String, ByVal lastName As String) As String
Dim employeeID As String = $"{GetPartOfName(firstName, 4)}{GetPartOfName(lastName, 4)}{DateTime.Now.Millisecond.ToString()}"
Return employeeID
End Function
Private Function GetPartOfName(ByVal name As String, ByVal numberOfCharacters As Integer) As String
Dim output As String = name
If name.Length > numberOfCharacters Then
output = name.Substring(0, numberOfCharacters)
End If
Return output
End FunctionTim aktualisiert die Unit-Tests, um Änderungen im Code zu berücksichtigen, wie z. B. die Änderung der erwarteten Länge von Teilstrings. Er erklärt, wie die Durchführung dieser Tests hilft, Probleme schnell zu erkennen und zu überprüfen, ob der Code den neuen Anforderungen entspricht. Tim fügt neue Theorien hinzu und führt dann die Unit-Tests aus, um zu überprüfen, ob die Ergebnisse den Erwartungen entsprechen:

Um die Vielseitigkeit Ihrer Klassenbibliothek zu erhöhen, empfiehlt Tim Corey den Übergang von einer .NET Framework-Klassenbibliothek zu einer .NET Standard-Klassenbibliothek. Diese Änderung ermöglicht die Kompatibilität der Bibliothek auf verschiedenen Plattformen, einschließlich:
Neues Projekt hinzufügen: Klicken Sie mit der rechten Maustaste auf Ihre Lösung und wählen Sie "Neues Projekt hinzufügen".
Wählen Sie .NET Standard: Wählen Sie anstelle einer .NET Framework-Klassenbibliothek den .NET Standard. Dieser Bibliothekstyp unterstützt eine breite Palette von Plattformen.

Code-Migration: Kopieren Sie Ihren vorhandenen Code (z. B. die EmployeeProcessor-Klasse) und fügen Sie ihn in die neue .NET Standard-Bibliothek ein. Dieser Prozess kann geringfügige Anpassungen beinhalten, aber die Kernlogik bleibt konsistent.
Durch die Konvertierung in den .NET Standard machen Sie Ihre Bibliothek von verschiedenen Plattformen aus zugänglich, verringern die Wiederholung von Code in verschiedenen Anwendungstypen und sparen Entwicklungsaufwand.
Tim Corey betont, dass Sie durch die Einführung einer .NET Standard-Bibliothek die Wiederholung von Code nicht nur in Ihrer Codebasis, sondern auch im Entwicklungsprozess minimieren. Anstatt Code in verschiedenen plattformspezifischen Projekten zu duplizieren, zentralisieren Sie ihn in einer einzigen Bibliothek, die in mehreren Umgebungen funktioniert.
Testen und Debuggen: Tim stellt Unit-Tests als eine Möglichkeit vor, den Aufwand und die Wiederholungen weiter zu reduzieren. Automatisierte Tests überprüfen die Korrektheit Ihres Codes, ohne dass Sie jede Iteration der Anwendung manuell testen müssen.
Tim Corey betont, dass die Befolgung des DRY-Prinzips (Don't Repeat Yourself) für das Schreiben von wartbarem Code von entscheidender Bedeutung ist, dass man aber auch wissen muss, wann und wo man es anwendet. Nicht jedes Szenario erfordert die gleiche Herangehensweise, daher finden Sie hier einige praktische Tipps, die von Tims Erkenntnissen inspiriert sind:
Vermeiden Sie Code in Code-Behind und UI: Tim rät davon ab, Logik direkt in den Code-Behind-Dateien oder Benutzeroberflächen zu platzieren. So sollte beispielsweise keine Geschäftslogik in ein Formular oder ein Schaltflächenklick-Ereignis eingebettet werden. Bewahren Sie diese Logik stattdessen in separaten Klassen oder Bibliotheken auf. Diese Trennung hilft, eine saubere Architektur aufrechtzuerhalten und macht Ihren Code über verschiedene Benutzeroberflächen hinweg wiederverwendbar.
Nutzen Sie .NET Standard-Bibliotheken: Beim Erstellen von Bibliotheken empfiehlt Tim, wenn möglich .NET Standard-Bibliotheken anstelle von .NET Framework-Bibliotheken zu verwenden. .NET Standard-Bibliotheken sind vielseitiger und ermöglichen die Verwendung Ihres Codes auf verschiedenen Plattformen, einschließlich .NET Core, Xamarin und anderen. Dieser Ansatz reduziert die Duplizierung von Code und verbessert die Portabilität des Codes.
Separater plattformspezifischer Code: Einige Codes passen aufgrund plattformspezifischer Anforderungen, wie z. B. Dateiverarbeitung oder Konfigurationsmanagement, möglicherweise nicht in eine .NET Standard-Bibliothek. Tim empfiehlt, in solchen Fällen zwei Bibliotheken zu erstellen: eine für .NET Standard Code und eine weitere für plattformspezifischen Code. Auf diese Weise können Sie die Kernlogik wiederverwenden und gleichzeitig die plattformspezifischen Anforderungen berücksichtigen.
Emphasize Unit Testing: Tim rät dringend dazu, Unit-Tests für Ihren Code zu schreiben. Unit-Tests helfen dabei, Fehler frühzeitig zu erkennen und sicherzustellen, dass sich Ihr Code wie erwartet verhält. Sie können den Debugging-Prozess erheblich beschleunigen, da Sie Änderungen schnell verifizieren können, ohne die gesamte Anwendung manuell testen zu müssen.
Berücksichtigen Sie die Projektgröße: Bei sehr kleinen oder experimentellen Projekten erkennt Tim an, dass der Aufwand für die Erstellung separater Bibliotheken und umfangreicher Unit-Tests möglicherweise nicht notwendig ist. Für Produktionsanwendungen ist es jedoch ratsam, mit einer sauberen Architektur und Unit-Tests zu beginnen, da kleine Projekte oft mit der Zeit wachsen und sich weiterentwickeln.
Wenn Sie diese Tipps befolgen, können Sie das DRY-Prinzip effektiv anwenden und gleichzeitig einen Ausgleich zwischen der Notwendigkeit der Wiederverwendung und der Wartbarkeit von Code und praktischen Erwägungen schaffen.
Die Beherrschung des DRY-Prinzips durch Entwurfsmuster ist für das Schreiben von sauberem und wartbarem C#-Code unerlässlich. Wie von Tim Corey gezeigt, beinhaltet die effektive Anwendung von DRY die Erstellung wiederverwendbarer Methoden, die Nutzung von Klassenbibliotheken und die Einbeziehung des .NET Standards für eine breitere Kompatibilität. Wenn Sie verstehen, wann und wie Sie diese Praktiken anwenden, können Sie die Qualität und Flexibilität Ihres Codes erheblich verbessern.
Weitere Informationen finden Sie in Tim Coreys Video zu diesem Thema hier. Um mit Tims neuesten Inhalten auf dem Laufenden zu bleiben, besuchen Sie seinen YouTube-Kanal.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy