Extension Methods vs. Reflection

Reflection bezeichnet (nicht nur im .Net Bereich) die Möglichkeit, zur Laufzeit die Metainformationen einer Anwendung zu nutzen. Fragestellungen wie „Wieviele Properties hat die Klasse?“ können beantwortet werden, ohne dass die reflektierte Klasse zur Programmierzeit bekannt ist/war. Für die alltägliche Businesslogik eignet sich Reflection nur bedingt –  wohl aber für allerlei Querschnittsaufgaben. Auditing, Logging oder dynamische Oberflächen werden damit möglich.

Extension Methods wurden mit .Net 3.5 eingeführt und erlauben es einen Type zu erweitern ohne von ihm abzuleiten. So können bequem sogar „sealed“ Types wie System.String erweitert werden – z.B. um eigene Substring Funktionen. Eine ebenfalls sehr nützliche Funktionalität ist es (generische) Interfaces mit konkretem Code zu hinterlegen, ohne alle Ableitungen des Interfaces zu überarbeiten zu müssen. Eine Extension Method zu IList erweitert also sofort alle Klassen die darauf aufbauen.

Das alles macht im ersten Moment den Eindruck einer Mehrfachvererbung. Das suggeriert auch Visual Studio, indem es die Extension- mit den Instanz-Methoden zusammen anzeigt:extensionmethod_multipleinheritance_visualstudioIn Wirklichkeit handelt es sich aber nur um „Syntax Sugar„, also einer reinen Vereinfachung für den Programmierer – intern sind das verschiedene Klassen.

Das hat mehrere Konsequenzen:

  • Extension Methods können keine Interfaces implementieren
  • sie können keine abstracten Methoden ausprogrammieren
  • per Reflection sind Extensions nicht in der eigentlichen Klasse zu finden

Der Versuch die Extension auf normalem Wege per Reflection zu finden scheitert:

MethodInfo method = typeof(MyClass)
   .GetType()
   .GetMethod("ExtensionMethod");
Assert.IsNotNull(method); //Dieser Test wird scheitern

Die gesuchte Methode ist eben nicht im gleichen Typ definiert, sondern in einer beliebigen anderen Klasse.

Um alle Extension Methods zu einer bestimmten Klasse zu finden, ist es notwendig alle Typen der Assembly (oder AppDomain) nach Methoden zu durchsieben die zum gesuchten Type („TypeToSearchFor“) erfüllen:

var methods = TypeToSearchFor.Assembly
  .GetTypes()
  .Where(t =>
       t.CustomAttributes
       .where(a => a.AttributeType == typeof(ExtensionAttribute))
       .Count() == 1
       )
  .SelectMany(t => t.GetMethods())
  .Where(m=>m.IsStatic == true)
  .Where(m => m.GetParameters().Count() != 0)
  .Where(m => m.GetParameters()[0].ParameterType == TypeToSearchFor)
  ;

Als Anhang befindet sich ein Testprojekt mit :

  • BeispielKlasse und Extension dazu
  • TestProjekt mit Reflection zum Suchen der Methoden
  • ReflectionHelper Klasse zum Suchen aller Extension Methods
Dieser Beitrag wurde unter .Net, Allgemein veröffentlicht. Setze ein Lesezeichen auf den Permalink.