Reflection – einige Hilfen

Sobald ich generisch programmieren muß und dabei Methoden oder Properties ansprechen von Objekten, die ich noch nicht kenne, kann man leicht recht viel Zeit verlieren, wenn man nicht dauernd damit arbeitet. Hier ein paar Hilfen für die, denen es so geht…

Type aus Objekt / aus Klasse / aus String erzeugen!

Das Type-Objekt ist ja die zentrale Ausgangsstelle für alles, was mit Reflection zu tun hat – zum einen gewinne ich meine MethodInfo, PropertyInfo etc. daraus, zum anderen benötige ich Types um Parameter einer Methode anzugeben. Darum sollte ich aus allen eventuell vorliegenden Quellen wissen, wie ich jeweils Type-Objekte erzeuge.

Aus Objekt: myObject.GetType()

Dies ist sicherlich am geläufigsten, da man bei jedem Objekt auf .GetType() stößt, eine Methode, die bereits in der Basisklasse Object verfügbar ist. Außerdem wird dies auch am häufigsten benötigt: Führe Methode xy von Objekt z aus oder setze den Wert der Property xy von Objekt z.

string myObject = "DasIstMeinTest";
System.Reflection.MethodInfo miToLower = myObject.GetType().GetMethod("ToLower");

Dabei aber nicht mißverstehen – diese so erzeugte MethodInfo hat natürlich trotzdem nichts mit der spezifischen Instanz des Objekts zu tun, auch wenn ich aus dem Objekt den Type geholt habe. Darum muß ich auch beim Ausführen z.B. eines Invoke dieser Methode das eigentliche Objekt nochmal mitgeben.

var ob = mi.Invoke(myObject,null);

Aus Klasse: typeof(myClass)

Der obige Ausdruck myObject.Gettype() ist gleichbedeutend mit

MethodInfo miToLower = typeof(string).GetMethod("ToLower");

Typischweise habe ich noch kein Objekt, wenn ich z.B. die erforderlichen Parameter an GetMethod übergeben muß (um eine MethodInfo der richtigen Überladung der Methode zu erhalten). Dort sieht man dann typeof:

MethodInfo mi2 = typeof(string).GetMethod("SubString",
         new Type[]
         {
                 typeof(Int32),
                 typeof(Int32)
         });
var result2 = mi2.Invoke(myObject, 
         new object[] 
         {
                 2, 
                 3 
         });

Aus String: Type.GetType(„MyClassName„)

Ich habe häufig Konstellationen, wo weder Klasse noch Objekt vorliegt, sondern z.B. der KlassenName in einer string-Variablen (z.B. nachdem er durch Stringbearbeitung aus einem anderen Klassennamen erhalten worden ist).

this.mainDataType = Type.GetType("WLP.WLPServiceReference.WLP" + this.centralMainEntity);

Achtung: Die gesamte Assembly-Referenz ist nötig, da das using Statement hier keinen Niederschlag findet. Zur Sicherheit ist der erzeugte Type anschließend auf null zu prüfen (da durch den Compiler bei Reflection ja keine Prüfung stattfinden kann). Dies empfiehlt sich bei allen „unsicheren“ Reflection-Abfragen.

Das Ergebnis ist ebenso eine Type, mit dem ich nun weiterarbeiten kann.

Generische Methode (mit Type-Parameter) ansprechen

string retVal = myObject.MyTypeParameteredMethod<string>("abc");

Möchten wir diesen Code generalisieren, also via Reflection ansprechen, müssen wir uns mit MakeGenericMethod vertraut machen. Der Code dazu würde so aussehen:

MethodInfo mi = typeof(MyClass).GetMethod("MyTypeParameteredMethod");
MethodInfo mig = mi.MakeGenericMethod(new Type[] { typeof(string) });
var retValue = mig.Invoke(new MyClass(), new[] { "TestStringParameter" });
Console.WriteLine(retValue);

MakeGenericMethod ist also eine Methode der MethodInfo-Klasse, die wiederum eine MethodInfo zurückgibt, aber eine „bessere“, die ich dann benutzen kann zum ansprechen der entsprechenden generischen Methode.

Achtung extension method! (z.B. IEnumerable.Cast<>)

Es mag sein, daß ich alles richtig gemacht habe, um eine MethodInfo mit EineKlasse.GetType().GetMethod(„EineMethode“) zu holen, aber trotzdem null zurück erhalte. Hier findet sich dann häufig der Grund darin, daß diese Methode eine extension method ist.

Ein typisches Beispiel ist die IEnumerable.Cast<MyClass>, was ich im Zusammenhang mit Ria Services und Silverlight häufig benötige, um die vom RiaService kommende IEnumerable-collection in einen eigenen Typ zu casten. Folgender Code schlägt fehl.

MethodInfo mi = this.ddsMain.Data.GetType().GetMethod("Cast"); 
//hier ist ddsMain eine DomainDataSource, ihre Data-Property also eine IEnumerable
MethodInfo mi = typeof(IEnumerable).GetType().GetMethod("Cast");
//dies wäre gleichbedeutend.

Der Grund findet sich schnell, wenn ich mir die Methoden in Inellisens ansehe.

Der Pfeil nach unten beim Symbol für die Cast<>-Methode zeigt gleich an, daß dies eine extension-Method ist. Diese gehört nicht wirklich zur Klasse IEnuerable dazu, sondern zu der Klasse, wo sie definiert wurde, das ist im Fall von cast System.Linq.Enumerable. Wir erhalten also unsere MethodInfo mit

MethodInfo mi = typeof(System.Linq.Enumerable).GetMethod("Cast"); 

Bleibt noch das ausführen der eigentlichen Methode. Hier muß an Invoke als 1. Parameter null übergeben werden, da extension methods eigentlich statische Methoden sind, auch wenn sie als nicht-statisch auftreten. Der vollständige Code lautet also

MethodInfo mi = typeof(System.Linq.Enumerable).GetMethod("Cast");
Type[] typeParameters = new Type[] { Type.GetType("WLP.Web.ArtikelV") };
//hier ist ArtikelV meine typisierte IEnumerable-Klasse
MethodInfo gmi = mi.MakeGenericMethod(typeParameters);
WLP.Web.ArtikelV value = gmi.Invoke(null, new[] {this.ddsMain.Data});
Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

w

Verbinde mit %s

%d Bloggern gefällt das: