[C#] Extensions

02/14/2013 12:58 Popicker#1
Mit dem .NET Framework 3.0 hat Microsoft eine Möglichkeit geschaffen bestehende Klassen einfach zu erweitern. An sich ist es kein Problem eigene Klassen zu erweitern, so lange man den Quellcode zur Verfügung hat. Fremde Klassen zu erweitern ist dagegen schnell problematisch. Entweder weil man den Quellcode nicht zur Verfügung hat oder weil es der Author untersagt dessen Code zu verändern.

An dieser Stelle könnte man natürlich einfach eine eigene Methode schreiben. Der Nachteil daran ist, dass man die eigentliche Funktionalität einer Klasse in eine andere trennt und somit die Verbindung schwerer nachzuvollziehen ist.

Mit dem .NET Framework 3.0 kann man sogenannte Extensions schreiben und somit bestehende Typen erweitern. Als erstes Beispiel wollen wir den Typ string so erweitern, dass er eine Methode zur Verfügung stellt die den Inhalt der string Variable als Textdatei an einem Ort speichert, der per Parameter übergeben wird. Das Ziel ist also, dass wir folgenden Code schreiben können und somit den gewünschten Effekt erzielen:

Code:
string text = "Dieser Text soll in eine Textdatei gespeichert werden.";
text.ToFile(@"C:\tutorial\MyNewTextFile.txt");
Um einen Typen erweitern zu können benötigen wir eine neue Klasse. In Visual Studio macht man dazu einfach einen Rechtsklick auf ein Projekt oder Ordner und dann "Add" -> "Class". Als Namen würde ich "StringExtension" vorschlagen.
Wenn ihr die Klasse erstellt habt müsst ihr Sicherstellen, dass die Klasse statisch ( static ) ist. Als erstes löscht ihr den Standard Konstruktor der euch von Visual Studio erzeugt wurde. Anschließend solltet ihr eure Using Statements um den Namespace System.IO erweitern, immerhin wollen wir eine Textdatei erstellen.
Man mag sich wahrscheinlich wundern woher nun die Information kommt mit der festgelegt wird welchen Typen wir erweitern wollen. Bisher haben wir das auch noch nicht definiert. Das macht man erst bei der Methode die einen Typen erweitert. Unsere Methode sieht beispielsweise so aus:

Code:
public static void ToFile (this string content, string path)
Durch das Schlüsselwort "this" vor dem Typen des ersten Parameters definieren wir, dass wir den Typ string erweitern wollen. Das Schlüsselwort this sollte jedem bekannt sein. Die Methode hat nun zwei Parameter, welche wir wie gewohnt nutzen können. Interessant ist hier jedoch, dass wir den Parameter der mit "this" markiert ist nicht beim Aufruf der Methode übergeben, sondern dieser das Objekt selbst darstellt. Um unser Ziel nun zu erreichen müssen wir unsere Methode natürlich noch erweitern.

Code:
public static void ToFile (this string content, string path)
{
	if(string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");

	string directory = Path.GetDirectoryName(path);
	if(!Directory.Exists(directory)) Directory.CreateDirectory(directory);

	using (TextWriter writer = File.CreateText(path)) {
		writer.Write(content);
	}
}
Mit dieser Extension des Typs string können wir nun die Methode ToFile bei string Objekten aufrufen.

Im Quellcode habe ich noch ein paar andere nützliche string Methoden untergebracht, aber letztlich sind euch nicht viele Grenzen gesetzt.

Den Download zum Projekt findet ihr hier ( Das Projekt wurde mit MonoDevelop erstellt ): [Only registered and activated users can see links. Click Here To Register...]

LG und HTH
02/14/2013 13:20 Schlüsselbein#2
writer.Close() ist redundant, da du ja bereits die using-Klausel verwendest.

Abgesehen davon ist dein Beispiel nicht gerade gut gewählt, da es auch kürzer ohne Extension geht:
File.WriteAllText("C:\file.txt", "foobar");
02/14/2013 13:31 Popicker#3
Hallo Schlüsselbein,

du hast offenbar Recht, dass die Close Methode ebenfall die Dispose Methode aufruft. Wusste ich ehrlich gesagt nicht.

Das Beispiel soll nur veranschaulichen wie man Typen erweitert. Ich gebe dir Recht, es gibt Bessere Beispiele, doch dieses hier ist Simpel und im Quellcode habe ich noch einige andere, durchaus sinnvollere Erweiterungen des Typs string geliefert.

Die von dir angemerkte Redundanz habe ich aus dem Post entfernt, jedoch nicht im Quellcode.

[EDIT]
Du hast etwas unrecht. Ich habe mir die Methode WriteAllText() angeschaut. Diese stellt nicht sicher, dass die Directory vorhanden ist und wirft im Fall des nicht Vorhanden seins eine Exception. Somit hat diese Extension schon eine gewisse Daseinsberechtigung.