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

Productivity Power Tools für VS2010

Der neue Add Reference-Dialog erleichtert die Arbeit...

„Productivity Power Tools“ ist ein Add-On für Visual Studio 2010 mit einer Menge Features, die schlicht und einfach nicht rechtzeitig fertig geworden sind für das Hauptprodukt. Sollte jeder, der mit Visual Studio arbeitet, installiert haben.
Wenn man es einmal angefangen hat zu benutzen, fragt man sich, warum es doch so verhältnismäßig unbekannt ist und von vielen nicht genutzt. Vielleicht liegt es daran, daß es so schwer zu finden ist – ich habe schon eine Weite gegoogelt um auf den Download-Link zu stoßen; hier ist er: http://visualstudiogallery.msdn.microsoft.com/en-us/d0d33361-18e2-46c0-8ff2-4adea1e34fef . Dort befindet sich auch eine komplette Feature-Beschreibung, die sich für den Englsch-Leser auf jeden Fall lohnt einmal durchzustudieren. Hier meine Lieblings-Features, für die ich es schon mal auf jeden Fall empfehlen würde: 


Quick Access Fenster (Ctrl+3)

– „Wo war das nochmal im Menü zu finden???“ – die Frage schon mal gestellt? Das hat sich hiermit erledigt. Eingetippt und schon zeigt sich der Menüpfad, z.B. „Debug -> Windows -> Immediate (Ctrol+D, I)“. Der Hotkey wird auch gleich noch angezeigt.
– Vor allem für Blind-Tipper ist das Tool endlich die Möglichkeit wirklich kaum mehr das Menü anklicken zu müssen und auch sonst schnell da hin zu kommen, wo man will (z.B. eins der offenen Dokumente auszuwählen ohne Maus). Man muß sich nur einmal an die etwas stakselige Ctrl+3 gewöhnen (läßt sich greifen mit Ctrl auf linkem kleinen Finger und 3 auf Mittelfinger 🙂 ) – dann wird das Fenster schnell zum dauernden Begleiter.    

Solution Navigator

Solution Navigator - Weiterentwicklng des Solution Explorer

Ein weiterentwickelter Solution Explorer bei dem ich  

– von den Dateien weiter aufklappen kann in die enthaltenen Klassen, von denen in die enthaltenen Members (Properties, Methoden…)
– Sehr einfach das Projekt durchsuchen kann, dabei wird dann jeder Knoten aufgeklappt, bei dem das Wort enthalten ist in Member-Namen oder Datei-Namen.
– Filtern nach allen offenen oder bearbeiten Dateien. Hat sich für mich als sehr praktisch erwiesen…

„Auto Brace Support“ – Erleichterung beim Tippen

Als ich angefangen habe, mit Visual Studio zu arbeiten, habe ich mich oft gefragt: Das kann doch nicht etwa wirklich so gemeint sein, wie ich meine geschweiften Klammern zusammenbaue, um überhaupt mal eine Procedure zu schreiben, machen das andere etwa auch so? Sicherlich, mit Code Snippets & Co komm ich schneller zum Ziel, aber für die tägliche Arbeit hilft der „Auto Brace Support“ schon: Bei jeder { [ ( < und Anführungszeichen entsteht das schließende Pendant UND (wichtig) mit Tab hüpfe ich weiter.  Gewöhnt man sich schnell dran.   

SEHR verbesserte Tabulator-Ansicht der offenen Dateien

So praktisch fand ich die neue Anzeige VS2010 nicht – wenn ich mehrere Dateien schließen wollte, hüpfte der X button (der jetzt im einzelnen Tabultor drin war) je nach Länge des Namens… Das ist hier gefixt, aber eine Menge mehr! Die für mich wichtigsten Verbesserungen dabei sind:    



Tabulator-Ansicht nach Installation der Productivity Power Tools

– Einzelne Tabs sind Pin-bar und optional die gepinnten in extra Reihe anzuzeigen. Ich empfehle die Einstellung so vorzunehmen (direkt von den Tabs aus ganz rechts in Tab-Leiste Pfeil nach unten, Customize…) daß „Show Pin button in unpinned tabs“ ausgeschaltet wird, denn dies nimmt Platz für die Dateibezeichnung, selbst wenn gerade nicht sichtbar, weil die Maus nicht darüber liegt (siehe hier in der Abbildung, wo dies nicht ausgeschaltet war, die …-Abkürzungen der Namen). Wenn es ausgeschaltet ist, kann immer noch einfach über das Kontextmenü „gepinned“ werden.

– Die min und max-Größe der Tabs läßt sich einstellen – Achtung, in Optionen erst nicht sichtbar, abwärts scrollen! Ich empfehle die Größe so einzustellen, daß „Min“ sehr kleine (50 – für kurze Dateinamen) und „Max“ immer noch erträglich große Dateinamen darstellen kann (200).

– Der „dirty-flag“ läßt sich einstellen. Leider nicht so, daß er direkt mit * am Dateinamen hängt – vielleicht demnächst.

– Der Tab erhält eine Farbe in Abhängigkeit z.B. vom Projekt (oder von Regular Expression). Sehr nützlich ist das, wenn man in der typischen Konstellation in Silverlight-Anwendungen arbeitet mit einem UI-Projekt in Silverlight und einem Web-Projekt für die Webservices, so daß man immer sofort weiß, wo man ist.   



Guidelines zur Orientierung

   

Guidlines zur Orientierung

Hier können wir gleich mal „Quick Access“ üben: Ctrl+3 und „Add Guidline“ eintippen. An der aktuellen Cursorposition entsteht die Guideline. Dies ist bei längeren Code-Files (besonders auch bei XAML!!!) sehr hilfreich, zum Beispiel wenn mehrere Blöcke umsortiert werden müssen, um zu überprüfen, was Bereiche auf der gleichen Einrückungsebene liegen. 

Hilfreiches für den Text-Editor!!!

– Aktuelle Linie wird farblich hervorgehoben (Einstellbar unter Tools / Options / Fonts & Colors als „Current Line (Extension)“ und „Current Line Inactive (Extension)“.- Ctrl + Maus über Methodenname macht einen Hyperlink draus und läßt mich bei Click schneller dahin navigieren (statt „Go To Definition“ im Kontextmenü) – Alt+Pfeil hoch/runter verschiebt die Zeile (auch praktisch…) – der altgewohnte Close-Button ganz rechts, der es einem doch einfacher macht, mehrere Files nacheinander manuell zu schließen.

Endlich ein ordentlicher Add Reference-Dialog

(siehe Abbildung oben) Der „originale“ hat sicherlich jedem schon Verdruß bereitet. Der neue kann z.B. endlich suchen, die letzten anzeigen und eine Menge mehr. Achtung: Bei doppelklick auf eine Referenz (fügt sie im Hintergrund hinzu und kennzeichnet das durch einen grünen Haken:) Nicht wundern, daß das dauert, ohne daß etwas angezeigt wird…