2008-09-06 7 views
10

Ich habe über die Angemessenheit der Reflexion in C# -Code gefragt. Zum Beispiel habe ich eine Funktion geschrieben, die durch die Eigenschaften eines gegebenen Quellobjekts iteriert und eine neue Instanz eines bestimmten Typs erstellt und dann die Werte von Eigenschaften mit demselben Namen von einem zum anderen kopiert. Ich habe dies erstellt, um Daten von einem automatisch generierten LINQ-Objekt in ein anderes zu kopieren, um die fehlende Vererbung von mehreren Tabellen in LINQ zu umgehen.Begründung für die Reflexion in C#

Aber ich kann nicht helfen, aber denken, dass Code wie dieser wirklich "betrügt", d. H., Anstatt die bereitgestellten Sprachkonstrukte zu verwenden, um ein gegebenes Ende zu erreichen, erlaubt es Ihnen, sie zu umgehen.

Inwieweit ist diese Art von Code akzeptabel? Was sind die Risiken? Was sind legitime Anwendungen dieses Ansatzes?

Antwort

1

Es mag nur ich sein, aber die Art und Weise, wie ich in dieses einsteigen würde, ist durch die Erstellung eines Code-Generators - die Verwendung von Reflektion zur Laufzeit ist ein wenig teuer und untypisiert. Wenn Sie Klassen erstellen, die nach Ihrem neuesten Code generiert werden, und alles in stark typisierter Weise kopieren, bedeutet dies, dass Sie diese Fehler während der Erstellung erfassen.

Zum Beispiel kann eine generierte Klasse kann wie folgt aussehen:

static class AtoBCopier 
{ 
    public static B Copy(A item) 
    { 
     return new B() { Prop1 = item.Prop1, Prop2 = item.Prop2 }; 
    } 
} 

Wenn eine Klasse nicht über die Eigenschaften oder deren Typen zu ändern, wird der Code nicht kompilieren. Plus, es gibt eine enorme Verbesserung der Zeiten.

2

Ich stimme zu, es gibt mir die es funktioniert, aber es fühlt sich an wie ein Hack Gefühl. Ich versuche, Reflexionen zu vermeiden, wann immer es möglich ist. Ich wurde viele Male nach dem Refactoring-Code verbrannt, der darin reflektiert wurde. Code kompiliert gut, Tests laufen sogar, aber unter besonderen Umständen (die die Tests nicht abgedeckt haben), sprengt das Programm die Laufzeit, weil ich in einem der Objekte, in die der Reflektionscode hineingestopft ist, refactoriert habe.

Beispiel 1: Reflektion in OR-Mapper, Sie ändern den Namen oder den Typ der Eigenschaft in Ihrem Objektmodell: Blows run-time.

Beispiel 2: Sie befinden sich in einem SOA-Shop. Web Services sind vollständig entkoppelt (oder Sie denken). Sie haben ihre eigene Reihe von generierten Proxy-Klassen, sondern in dem Mapping entscheiden Sie einige Zeit zu sparen und Sie dies tun:

ExternalColor c = (ExternalColor)Enum.Parse(typeof(ExternalColor), 
              internalColor.ToString()); 

Unter den Abdeckungen dies auch Reflexion ist, sondern durch die .net Framework selbst getan. Was passiert nun, wenn Sie beschließen, InternalColor.Grey zu InternalColor.Gray umzubenennen? Alles sieht gut aus, es baut gut und läuft sogar gut .. bis zu dem Tag, an dem sich ein blöder Benutzer entscheidet, die Farbe Grau zu verwenden ... an diesem Punkt wird der Mapper explodieren.

8

Manchmal kann die Verwendung von Reflektion ein bisschen wie ein Hack sein, aber oft ist es einfach das fantastischste Code-Tool.

Sehen Sie sich das .Net-Eigenschaftsraster an - jeder, der Visual Studio verwendet hat, wird damit vertraut sein. Sie können es auf jedes Objekt richten und es wird einen einfachen Eigenschaftseditor erzeugen. Das nutzt Reflektion, in der Tat die meisten VS-Toolbox.

Schauen Sie sich Unit-Tests an - sie werden durch Reflektion geladen (zumindest in NUnit und MSTest).

Reflection ermöglicht dynamisches Verhalten von statischen Sprachen.

Die eine Sache, die es wirklich braucht, ist Ente tippen - der C# Compiler unterstützt dies bereits: Sie können foreach alles, was wie IEnumerable aussieht, ob es die Schnittstelle implementiert oder nicht. Sie können die C# 3-Auflistungssyntax für jede Klasse verwenden, die über eine Methode namens Add verfügt.

Verwenden Sie Reflektionen, wo auch immer Sie dynamisches Verhalten benötigen - zum Beispiel haben Sie eine Sammlung von Objekten und Sie möchten die gleiche Eigenschaft auf jedem prüfen.

Die Risiken sind für dynamische Typen ähnlich - Kompilierzeit-Ausnahmen werden Laufzeit-Einsen. Du Code ist nicht so "sicher" und du musst entsprechend reagieren.

Der .Net-Reflexionscode ist sehr schnell, aber nicht so schnell wie der explizite Aufruf gewesen wäre.

+0

Wenn ich gefragt würde, was die Vor- und Nachteile der Reflexion sind, wäre dies eine geeignete Antwort? –

1

Ich habe kürzlich in C# Reflektion verwendet, um Implementierungen einer bestimmten Schnittstelle zu finden. Ich hatte einen einfachen Batch-Interpreter geschrieben, der für jeden Berechnungsschritt nach dem Klassennamen "Aktionen" suchte. Wenn ich den aktuellen Namensraum reflektiere, erscheint die richtige Implementierung meiner IStep-Schnittstelle, die Execute() ed sein kann. Auf diese Weise ist das Hinzufügen neuer "Aktionen" so einfach wie das Erstellen einer neuen abgeleiteten Klasse - es muss nicht zu einer Registry hinzugefügt werden, oder noch schlimmer: Vergessen, es einer Registry hinzuzufügen ...

2

Reflection ist ein wunderbares Werkzeug ohne die ich nicht leben könnte. Es kann die Programmierung viel einfacher und schneller machen.

Zum Beispiel verwende ich Reflexion in meinem ORM-Layer, um Eigenschaften mit Spaltenwerten aus Tabellen zuweisen zu können. Wenn ich nicht nachdenken musste, musste ich für jede Tabelle/Klassenzuordnung eine Kopierklasse erstellen.

Wie für die externe Farbe Ausnahme oben. Das Problem ist nicht Enum.Parse, aber der Codierer hat die richtige Ausnahme nicht gefunden. Da eine Zeichenfolge analysiert wird, sollte der Codierer immer davon ausgehen, dass die Zeichenfolge einen falschen Wert enthalten kann.

Das gleiche Problem gilt für alle erweiterten Programmierung in .Net. "Mit großer Macht kommt große Verantwortung". Die Verwendung von Reflektion gibt dir viel Kraft. Aber stellen Sie sicher, dass Sie wissen, wie man es richtig benutzt. Es gibt Dutzende von Beispielen im Internet.

0

Reflection macht es sehr einfach, Plugin-Architekturen zu implementieren, bei denen Plugin-DLLs zur Laufzeit automatisch geladen werden (nicht explizit zur Kompilierungszeit verknüpft).

Diese können nach Klassen durchsucht werden, die relevante Schnittstellen/Klassen implementieren/erweitern. Die Reflexion kann dann verwendet werden, um Instanzen von diesen bei Bedarf zu instantiieren.