Das IDisposable-Pattern
Ich mag das Interface IDisposable. Vor allem mag ich das using-Konstrukt in C#. Für diejenigen, die diese beiden Dinge nicht kennen, ein kurzes Beispiel:
using (var connection = new SqlConnection("connectionString")) { // todo }
Die Klasse SqlConnection implementiert die Schnittstelle IDisposable und stellt daher eine öffentliche Dispose-Methode zur Verfügung. Am Ende des using-Blockes wird diese Methode dann aufgerufen. Konkret entspricht der Beispielcode diesem hier:
var connection = new SqlConnection("connectionString"); try { // todo } finally { connection.Dispose(); }
Die Kombination von IDisposable und using gibt mir als Entwickler nun eine elegante Möglichkeit, einen Codeabschnitt zu kapseln. In letzter Zeit nutzte ich dieses Pattern für mehrere Anforderungen. Beispielsweise wollte ein Kunde, dass Operationen, die länger dauern, eine Sanduhr am Mauszeiger anzeigen. Das sah dann so aus:
using (MouseCursorWrapper.Set(Cursors.Wait)) { // todo }
Sobald der lange dauernde Codeblock nun abgeschlossen ist, wird die Dispose-Methode aufgerufen. Der Mauszeiger soll dann wieder zurückgesetzt werden. Die Implementation des MouseCursorWrappers ist die folgende:
public sealed class MouseCursorWrapper : IDisposable { private MouseCursorWrapper(Cursor cursor) { Mouse.SetCursor(cursor); } public static IDisposable Set(Cursor cursor) { return new MouseCursorWrapper(cursor); } public void Dispose() { Mouse.SetCursor(Cursors.Arrow); } }
Für den gleichen Kunden habe ich auch Performance Messungen eingebaut.
using (StopwatchWrapper.Start("Test")) { Thread.Sleep(10); }
Diese Klasse sieht folgendermassen aus:
public class StopwatchWrapper : IDisposable { private readonly Stopwatch _stopwatch; private readonly string _label; private StopwatchWrapper(string label) { _label = label; _stopwatch = Stopwatch.StartNew(); } public static IDisposable Start(string label) { return new StopwatchWrapper(label); } public void Dispose() { _stopwatch.Stop(); Console.WriteLine("{0}: {1} ms", _label, _stopwatch.ElapsedMilliseconds); } }
Zusammen mit dem using-Statement erlaubt es die IDispose Schnittstelle, bestehenden Code auf eine saubere Art und Weise zu erweitern, ohne den bestehenden Code unnötig aufzublähen.