Reflection

Aus Das Sopra Wiki
Wechseln zu: Navigation, Suche

Mit Reflection kann ein Programm Kenntnisse über die eigene Struktur oder über die Struktur eines anderen Programmes erlangen. Dadurch wird es zum Beispiel möglich, eine Plug-In Architektur extrem einfach aufzubauen.

Klassen

Um eine Klasse zu untersuchen braucht man als erstes deren Typ. Dieser wird durch eine Instanz der Klasse Type[1] repräsentiert. Sie stellt die folgenden, für uns interessanten Methoden zur Verfügung:

GetMethods()
Gibt alle öffentlichen Methoden einer Klasse zurück. Diese werden durch MethodInfo[2]-Objekte beschrieben.
GetMethod(String methodName)
Gibt eine Methode, die durch einen Namen spezifiziert wurde zurück.
GetProperty(String name) und GetProperties()
Das Gleiche für Properties.
GetField(String name) und GetFields()
Das Gleiche für Felder
GetInterface(String name) und GetInterfaces()
Das Gleiche für Interfaces, die die Klasse implementiert.

Es gibt mehrere Möglichkeiten, um eine Type-Instanz zu bekommen:

1. Wenn man die Klasse kennt, aber jetzt noch kein Objekt erzeugen möchte, kann man das typeof-Schlüsselwort verwenden:

Type t = typeof(String);

2. Wenn man die Klasse nicht kennt, aber Zugriff auf eine Instanz dieser hat (z.B. nach Deserialisierung), kann die Methode GetType() verwendet werden:

 
String s = "Hallo reflective World"; 
Type t = s.GetType();

Methoden

Wenn man ein MethodInfo[2]-Objekt hat, kann man damit Methoden aufrufen. Dazu hat die Klasse eine Methode Invoke. Diese erwartet ein Objekt, auf dem die Methode aufgerufen wird und ein Array mit Parametern.

Type t = typeof(String);
MethodInfo mi = t.GetMethod("ToUpper");
Object result = mi.Invoke(s, new Object[] { });

result hat als Wert dann

HALLO REFLECTIVE WORLD

Allerdings gibt MethodInfo.Invoke immer ein Object zurück. man muss daher das Ergebnis casten.

Wenn eine Methode keinen Parameter erwartet kann man auch null statt des Arrays übergeben. Das gleiche gilt für statische Methoden, da wird null als erster Parameter übergeben.

Assemblies

Man kann neue Assemblies[3] laden indem man

Assembly a1 = Assembly.Load("Hier Name der Assembly als String angeben");
// oder
Assembly a2 = Assembly.LoadFile("Dateiname");

ausführt.

Aus Sicherheitsgründen sollte man, wenn möglich Assemblies nur mit ReflectionLoad* oder in ein andere AppDomain[4] laden.

Wichtige Hinweise

Das Aufzählen der Methoden, Properties und Felder unbekannter Klassen dauert extrem lang. Auch ist es schwer, ein venünftiges Caching dafür zu bauen. Auch wenn eine Methode ToString() für alle Objekte definiert ist kann man nicht die ToString-Methode der Klasse Game auf einem Objekt der Klasse GraphicsDevice aufrufen.

Der Compiler macht das Methoden aufrufen wesentlich besser, er kann diese dann auch optimieren und z.B. inlinen. Bei Verwendung von Reflection ist all das nicht möglich.

Video Tutorial

Auf MSDN gibt es einen Webcast zum Thema[5]

Referenzen