posted by: Ralf Rottmann | posted @ Monday, November 05, 2007 12:43 AM | View blog reactions

Dies ist der zweite Teil meiner Serie über neue Features des bevorstehenden "Orcas" Releases von .NET - dieses mal geht es um Extension Methods.

Betrachten wir einmal das folgende Codebeispiel, welches ohne Beanstandung kompiliert werden kann:

code

    1 string name = "Ralf Rottmann";
    2 if (name.IsRalfRottmann())
    3 {
    4     Console.WriteLine("Hey there, Ralf!");
    5 }

 

Man muss schon genau hinsehen: Seit wann exportiert der .NET Typ string eine Methode bool IsRalfRottmann()?

Die richtige Antwort ist natürlich, dass dies gar nicht der Fall ist. Das Beispiel zeigt die Anwendung von Extension Methods, auch wenn es zugegeben nicht unbedingt der gängigste Use Case ist, string um eine so simple Methode zu erweitern.

Nüchtern ausgedrückt erlauben Extension Methods die Erweiterung des öffentlichen Interfaces vorhandener Common Language Runtime (CLR) Typen ohne Ableitung neuer Klassen und ohne Neukompilierung. Die .NET Language Integrated Query (LINQ) Erweiterungen basieren unter anderem auf diesem neuen Sprachmerkmal.

Der folgende Codeauszug zeigt, wie die oben dargestellte Erweiterung umgesetzt wurde:

code

    1 namespace OrcasSamples24100
    2 {
    3     public static class MyExtensionMethods
    4     {
    5         public static bool IsRalfRottmann (this string s)
    6         {
    7             return (s.Equals("Ralf Rottmann"));
    8         }
    9     }
   10 }

 

Das "Geheimnis" ist also eine statische Klasse mit einer statischen Methode IsRalfRottmann(). Der kleine aber feine Unterschied zu herkömmlichen statischen Methoden ist das this Keyword vor dem ersten Methodenparameter. Dieses teilt dem C# Compiler mit, dass die Methode den vorhandenen string Typen erweitern soll. Innerhalb der Extension Method selbst kann auf alle öffentlichen Methoden, Events und Properties der Objektinstanz zugegriffen werden, auf welche die Extension Method angewendet wird.

Um die Extension Method zu "aktivieren" muss lediglich der Namensraum importiert werden, welcher die Definition enthält. Dazu dient das bekannte using Statement:

code

    1 using OrcasSamples24100;

 

Ab sofort kann der Compiler die neue Methode für alle string Objekte auflösen. Visual Studio 2008 bietet volle IntelliSense Unterstützung für Extension Methods:

image

Selbstverständlich bedeutet dies auch, dass sich der C# Compiler beschwert, falls der Name einer Extension Method Tippfehler enthält, oder die Parameterliste nicht stimmt.

Während das erste Codebeispiel bei erfahrenen .NET 2.0 Entwicklern vielleicht ein Schmunzeln verursacht, deutet die folgende Extension Method die Möglichkeiten anhand eines sehr praktischen Use Cases sehr viel besser an:

code

    1 public static bool IsValidEmailAddress(this string s)
    2 {
    3     Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
    4     return regex.IsMatch(s);
    5 }

 

Wird diese Extension Method importiert, sind statischer Hilfsmethoden in statischen Klassen à la

code

    1 string email = Request.QueryString["email"];
    2 
    3 if ( EmailValidator.IsValid(email) ) {
    4 
    5 } 

 

bald in weiten Teilen überflüssig und können durch die elegante Anwendung von Extension Methods abgelöst werden:

code

    1 string email = Request.QueryString["email"];
    2 
    3 if ( email.IsValidEmailAddress() ) {
    4 
    5 } 

 

Wie mächtig dieser Ansatz ist zeigt sich erst, wenn man nach ersten Experimenten komplexere Aufgabenstellungen damit löst. Nehmen wir einmal an, wir möchten für alle .NET Typen eine Möglichkeit bereitstellen, auf einfache Weise zu überprüfen, ob ein Objekt innerhalb einer Collection bereits existiert. Dazu können wir eine Extension Method für den Typ object implementieren - von dieser Mutter aller Basisklassen leiten ja alle .NET Typen ab.

code

    1 public static bool In(this object o, IEnumerable c)
    2 {
    3     foreach (object i in c)
    4     {
    5         if (i.Equals(o))
    6             return true;
    7     }
    8     return false;
    9 }

 

Der vorangegangene Code erweitert den Typ object ("this object o") und definiert als einzigen Methodenparameter einen Typ der das IEnumerable Interface implementiert, was für alle .NET Collection Types gilt. Die Anwendung dieser Extension Method könnte zum Beispiel so aussehen:

code

    1 string[] blogs = { "24100.net", "yauh.de", "blogs.msdn.com/expression/" };
    2 string searchBlog = "24100.net";
    3 
    4 if (searchBlog.In(blogs))
    5 {
    6 }

 

Tatsächlich lassen sich Extension Methods auch auf literale und skalare Typen anwenden (der C# Compiler übernimmt das Boxing und Unboxing):

code

    1 bool found = "yauh.de".In(blogs);

 

Von einigen .NET Entwicklern wurde die Befürchtung geäußert, Microsoft würde mit Extension Methods und anderen Erweiterungen C# (und VB) in die Richtung dynamischer Programmiersprachen gehen. Dem ist entgegenzuhalten, dass Extension Methods leistungsstarke Erweiterungen wie LINQ erst möglich machen, gleichzeitig aber volle Typsicherheit, compile time checking und volle Unterstützung für IntelliSense bieten.

In meinem nächsten Beitrag widmen wir uns einer weiteren faszinierende Erweiterung, den Lambda Expressions.

 

comments
No comments posted yet.
post your comment
Title *
Name *
Email
Url
Comment *  
Please add 2 and 8 and type the answer here: