Okay, nehmen wir an, wir haben eine Klasse definiert wie
%Vor%Dann versuchen wir:
%Vor% Die Kompilierung schlägt wie erwartet mit TestClass.MyPrivateProperty is inaccessible due to its protection level
fehl.
Versuchen Sie
%Vor%und Kompilierung schlägt erneut fehl, mit der gleichen Nachricht.
Alles gut bis jetzt, wir haben das erwartet.
Aber dann schreibe ich:
%Vor%und hier sind wir, wir haben es geschafft, ein privates Feld zu ändern.
Ist es nicht abnorm, den inneren Zustand eines Objekts nur durch Reflexion zu verändern?
Bearbeiten:
Danke für die bisherigen Antworten. Für diejenigen, die sagen "Sie müssen es nicht benutzen": Was ist mit einem Klassen-Designer, es sieht so aus, als könnte er nicht mehr von der inneren Sicherheit des Staates ausgehen?
Reflection bricht die Kapselungsprinzipien durch den Zugang zu privaten Feldern und Methoden, aber es ist nicht der erste oder einzige Weg, auf dem die Kapselung umgangen werden kann; Man könnte argumentieren, dass die Serialisierung alle internen Daten einer Klasse freigibt, Informationen, die normalerweise privat wären.
Es ist wichtig zu verstehen, dass die Kapselung nur eine Technik ist, die das Entwerfen von Verhalten erleichtert, vorausgesetzt, die Verbraucher stimmen zu, eine von Ihnen definierte API zu verwenden. Wenn jemand die API mithilfe von Reflektion oder einer anderen Technik umgehen möchte, hat er nicht mehr die Gewissheit, dass sich Ihr Objekt so verhält, wie Sie es entworfen haben. Wenn jemand einen Wert von null
einem privaten Feld zuweist, sollten sie besser bereit sein, ein NullReferenceException
zu fangen, wenn sie das nächste Mal versuchen, Ihre Klasse zu benutzen!
Nach meiner Erfahrung dreht sich bei der Programmierung alles um Behauptungen und Annahmen. Die Sprache behauptet Einschränkungen (Klassen, Schnittstellen, Aufzählungen), die das Erzeugen isolierten Verhaltens sehr viel einfacher machen, unter der Annahme, dass ein Konsument zustimmt, diese Grenzen nicht zu verletzen.
Dies ist eine faire Behauptung zu machen, vorausgesetzt, es macht einen Teil-und-herrsche Ansatz zur Software-Entwicklung einfacher als jede Technik davor.
Reflektion ist ein Werkzeug . Sie können es verwenden, um die Kapselung zu unterbrechen, wenn es Ihnen mehr bringt, als es wegnimmt.
Reflection hat einen gewissen "Schmerz" (oder Kosten - in Leistung, in Lesbarkeit, in der Zuverlässigkeit des Codes) damit verbunden, so dass Sie es nicht für ein allgemeines Problem verwenden werden. Es ist einfach einfacher objektorientierten Prinzipien für allgemeine Probleme zu folgen, was eines der Ziele der Sprache ist, die gemeinhin als die Grube des Erfolgs .
Auf der anderen Seite gibt es einige Aufgaben, die ohne diesen Mechanismus nicht lösbar wären, z. Arbeiten mit Laufzeit-Generatortypen (obwohl es sehr viel einfacher wird, beginnend mit .NET 4.0 mit seinem DLR und den "dynamischen" Variablen in C # 4.0).Ich nehme an, Sie könnten das sagen. Sie können auch sagen, dass die CodeDom-, Reflection-Emit- und Expression Tree-APIs die Kapselung unterbrechen, indem Sie Code direkt schreiben können. Sie sind lediglich Einrichtungen von .NET. Du musst sie nicht benutzen.
Vergessen Sie nicht, dass Sie (a) vollständig vertrauenswürdig sein müssen und (b) explizit BindingFlags.NonPublic
angeben müssen, um auf private Daten zugreifen zu können. Das sollte ein Sicherheitsnetz sein.
Sie haben Recht, dass die Reflexion einer beliebigen Anzahl von guten Designprinzipien entgegengesetzt werden kann, aber es kann auch ein wesentlicher Baustein sein, den Sie verwenden können, um gute Designprinzipien zu unterstützen - z. Software, die durch Plugins, Inversion der Kontrolle, etc. erweitert werden kann.
Wenn Sie befürchten, dass es sich um eine Funktion handelt, die nicht empfohlen werden sollte, haben Sie vielleicht einen Punkt. Aber es ist nicht so bequem wie echte Sprachfunktionen zu verwenden, so dass es einfacher ist, Dinge richtig zu machen.
Wenn Sie denken, Reflexion sollte unmöglich sein , träumen Sie!
In C ++ gibt es keine Reflexion als solche. Aber es gibt ein zugrunde liegendes "Objektmodell", das der compilergenerierte Maschinencode verwendet, um auf die Struktur von Objekten (und virtuellen Funktionen) zuzugreifen. So kann ein C ++ - Programmierer die Kapselung auf die gleiche Weise unterbrechen.
%Vor% Wir können einen Zeiger auf ein Objekt vom Typ RealClass
setzen und ihn einfach in FakeClass
umwandeln und auf das "private" Element zugreifen.
Jedes eingeschränkte System muss auf einem flexibleren System implementiert werden, so dass es immer möglich ist, es zu umgehen. Wenn die Reflektion nicht als BCL-Feature bereitgestellt wurde, konnte jemand sie mit einer Bibliothek mit unsicheren Code hinzufügen.
In einigen Sprachen gibt es Möglichkeiten, Daten zu kapseln, so dass es nicht möglich ist, innerhalb der Sprache zu erhalten, außer auf bestimmte vorgeschriebene Arten. Aber es wird immer möglich sein zu schummeln, wenn du einen Weg finden kannst, aus der Sprache zu entkommen. Ein extremes Beispiel wären Bereichsvariablen in JavaScript:
%Vor% Nach der Ausführung enthält der globale Namensraum zwei Funktionen, myGetter
und mySetter
, die die einzige Möglichkeit sind, auf den Wert von x
zuzugreifen. Javascript hat keine reflektive Fähigkeit, auf andere Weise auf x
zu kommen. Aber es muss in einer Art Host-Interpreter (z. B. im Browser) laufen, und so gibt es sicherlich eine schreckliche Möglichkeit, x
zu manipulieren. Ein Speicherfehler in einem Plugin könnte dies versehentlich verursachen!
Man kann sagen, dass Reflexion auch Vererbung und Polymorphie bricht. Wenn Sie nicht jeden Objekttyp mit einer eigenen überladenen Methodenversion versorgen, haben Sie eine einzige Methode, die den Objekttyp zur Laufzeit überprüft und zu einem bestimmten Verhalten für jeden Objekttyp wechselt.
Reflection ist trotzdem ein nettes Werkzeug. Manchmal müssen Sie ein Objekt mit einem privaten Konstruktor instanziieren, weil es eine optimale Vorgehensweise ist und Sie die Klassenimplementierung nicht ändern können (geschlossene Bibliothek, kann nicht mehr mit dem Autor in Kontakt treten). Oder Sie möchten einige Hilfsfunktionen für eine Vielzahl von Objekten an einem Ort ausführen. Oder vielleicht möchten Sie die Protokollierung für bestimmte Typen durchführen. Dies ist die Situation, in der die Reflexion hilft, ohne Schaden zu verursachen.
Das ist Teil der von Reflection gebotenen Funktionalität, aber ich würde sagen, es ist die beste Art, sie zu nutzen.
Es funktioniert nur unter voller Vertrauenswürdigkeit.
Das Einkapselungsprinzip wird von Ihrer API eingehalten, aber Reflektion gibt Ihnen die Möglichkeit, die API zu umgehen.
Wer die Reflektion nutzt, weiß, dass er Ihre API nicht korrekt verwendet!
Nein, es ist nicht unnormal.
Es ist etwas, was Reflektion Ihnen erlaubt, in einigen Situationen, was Sie getan haben, könnte es nützlich sein, in vielen anderen, die Ihren Code einfach zu einer Zeitbombe machen.
Reflexion ist ein Werkzeug, es kann benutzt oder missbraucht werden.
In Bezug auf die Frage nach Ihrer Bearbeitung: Die Antwort ist einfach nein.
Ein API-Designer könnte sein Bestes geben und viel Mühe darauf verwenden, eine saubere Schnittstelle offen zu legen und zu sehen, dass seine API durch Reflektion übermäßig missbraucht wird.
Ein Ingenieur kann eine perfekte Waschmaschine modellieren, die sicher ist, Sie nicht mit Elektrizität und so weiter schockiert, aber wenn Sie es mit einem Hammer zerschlagen, bis Sie die Kabel sehen, wird niemand den Ingenieur beschuldigen, wenn Sie kommen ein Schock: D
Reflection kann Ihnen helfen, Ihren Code sauber zu halten. Z.B. Wenn Sie Hibernate verwenden, können Sie die privaten Variablen direkt an DB-Werte binden, und Sie müssen keine unnötigen Setter-Methoden schreiben, die Sie sonst nicht benötigen würden. Von diesem Standpunkt aus kann Reflexion helfen, die Verkapselung aufrechtzuerhalten.
Tags und Links c# reflection oop