Liersch.Reflection – .NET-Bibliothek für bessere Performance

.NET bietet mit der Reflection-API eine einfache Möglichkeit, zur Laufzeit auf Typen und deren Elemente zuzugreifen. Typische Anwendungsfälle sind die Serialisierung und die Deserialisierung von Objekten. Bei der Serialisierung werden mit Hilfe der Reflection-API alle relevanten Felder und Eigenschaften eines Objektes in eine speicherbare Form wie JSON oder XML überführt. Die Deserialisierung stellt ein Objekt aus dieser speicherbaren Form wieder her.

Der Preis für das späte Binden von Typen und Elementen zur Laufzeit ist eine geringere Performance. Operationen, die normalerweise durch den Compiler erledigt werden, müssen bei Verwendung der Reflection-API zur Laufzeit erfolgen.

Liersch.Reflection verbessert die Performance der Reflection-API signifikant, indem für Konstruktor- und Funktionsaufrufe, sowie für Feldzugriffe dynamischer IL-Code erzeugt wird. Die Zugriffsgeschwindigkeit gleicht dadurch fast einem Direktzugriff. Es werden alle wichtigen .NET-Plattformen unterstützt (ab .NET Framework 2.0, ab .NET Core 2.0 und ab .NET Standard 2.1). Für ältere Projekte (vor .NET Framework 4.0) muss die Bibliothek manuell kompiliert und integriert werden.

Die Qualität der Bibliothek wird durch automatisierte Modultests sichergestellt. Für relevante Funktionen sind Modultests hinterlegt. Alle wesentlichen Bibliotheksänderungen werden in der Datei CHANGELOG.md protokolliert.

Features

Liersch.Reflection ist auf die Serialisierung und Deserialisierung von Objekten spezialisiert und stellt dafür die folgenden Features bereit:

  • schnelle Erzeugung von Klassen mit Hilfe des Standardkonstruktors
  • schnelle Erzeugung von Wertetypen
  • schnelles Aufrufen von Funktionen
  • schnelles Lesen und Schreiben von Eigenschaften
  • schnelles Lesen und Schreiben von Feldern

Die Bibliothek ist in C# 6.0 geschrieben. Die Dateigröße der kompilierten Bibliothek beträgt lediglich ≈20 kB.

Beispiel

Die Beispielanwendung verwendet Liersch.Profiling, um die Performance verschiedener Szenarien miteinander zu vergleichen. Die Messergebnisse zeigen den Geschwindigkeitsvorteil, der mit Liersch.Reflection erzielt werden kann. Die Performancemessung sollte außerhalb der Entwicklungsumgebung und auf Basis der Release-Version durchgeführt werden. Andernfalls beeinflusst der für das Debugging notwendige Zusatzaufwand das Messergebnis.

Integration

Liersch.Reflection beinhaltet die Klasse Accelerator, mit deren Hilfe Funktionszeiger für die schnelle Erzeugung von Typen, das schnelle Aufrufen von Funktionen und das schnelle Lesen und Schreiben von Eigenschaften und Feldern erzeugt werden können.

Statt Objekte mit Activator.CreateInstance zu erzeugen, muss nun der von Accelerator.CreateStandardConstructor gelieferte Funktionszeiger benutzt werden, um neue Instanzen zu erzeugen.

Func0 create=Accelerator.CreateStandardConstructor(type);
// ...
object inst=create();

Des Weiteren stehen einige ausgewählte Funktionen der Accelerator-Klasse alternativ als Erweiterungsfunktionen mit einer vereinfachten Signatur zur Verfügung.

InvocationDelegate toLower=typeof(string).CreateInvocationDelegate("ToLowerInvariant");
// ...
object o=toLower("Hello World!");

Für Funktionen mit bis zu zwei Parametern sind spezialisierte Funktionen verfügbar, die für die Parameterübergabe kein Array verwenden. Wenn nicht statische Funktionen aufgerufen werden, repräsentiert der erste Parameter stets die zu verwendende Instanz. Für die Manipulation von Wertetypen müssen diese vorher durch Boxing in den Heap-Speicher befördert werden (z. B. durch Typumwandlung nach object). Nur so ist sichergestellt, dass die Manipulationsfunktionen stets das gleiche Objekt bearbeiten und nicht bei jedem Zugriff eine neue Kopie verwenden. Eine Unterstützung von per Verweis übergebenen Parametern (siehe Schlüsselwort ref und out) ist nicht vorgesehen.

Die Verbesserung der Performance von Reflection-basierten Zugriffen erfolgt auf Basis von dynamisch generiertem Code. Der Aufwand der Codegenerierung lohnt sich nur dann, wenn eine höhere Anzahl von Zugriffen erwartet wird.

Lizenz

Die Veröffentlichung der Software erfolgt unter den Bedingungen einer Open-Source-Lizenz. Alternativ können im Rahmen einer kommerziellen Lizenz andere Bedingungen vereinbart werden. Sie können Pflege und Weiterentwicklung der Software mit einer freiwilligen Spende unterstützen.

Copyright

Copyright © 2020-2021 Steffen Liersch
https://www.steffen-liersch.de/

Verweise

Der Quellcode wird auf GitHub gepflegt:
https://github.com/steffen-liersch/Liersch.Reflection

Pakete können über NuGet heruntergeladen werden:
https://www.nuget.org/packages/Liersch.Reflection

Ähnliche Artikel

Schreiben Sie einen Kommentar