2016-11-22 1 views
0

Ich implementiere derzeit ein Typennamensauflösungsschema. Die verfügbaren Informationen sind sehr ähnlich zu dem, was man in einem normalen C# Source-Projekt bekommen würde:Dynamische Auflösung - mehrere Aufrufe von Type.GetType oder Scannen aller Typen in der Assembly?

  • eine Liste von Assembly Referenzen
  • eine Liste von using Namespaces

Zur Laufzeit für jeden Typen Namen Zum Auflösen ist der Name entweder vollständig qualifiziert (mit Namespace, aber nicht mit Assemblynamen) oder es handelt sich um einen einfachen Namen, von dem erwartet wird, dass er aus einem der Namespaces using stammt.

Um die Type passende jede Kennung zu finden, Ich erwäge eine von zwei Strategien:

  1. Preload alle Baugruppen mit Assembly.Load und alle Arten scannen. Alle einfachen Namen, die ein Namespacepräfix haben, das einem der Namespaces using entspricht, werden vorgeladen. Außerdem wird ein Dictionary erstellt, das jeden in der Assembly definierten Namen für den Namespace direkt der Type zuordnet. Die Konfliktlösung wird während der Ladephase entsprechend durchgeführt.

  2. Nicht vorladen. Wenn ein Typname eintrifft, versuchen Sie die folgende Sequenz:

    • Angenommen, der Name ist vollständig qualifiziert; Verknüpfen Sie nacheinander alle referenzierten Assemblynamen, um einen für die Assemblierung qualifizierten Namen zu erstellen, und rufen Sie Type.GetType auf, um zu sehen, ob wir einen gültigen Typ erhalten.

    • Wenn der obige Schritt keinen gültigen Typ erzeugt und der Name kein Präfix hat, wird angenommen, dass es sich um einen einfachen Namen handelt. Wiederholen Sie den obigen Schritt, aber jedes Mal den einfachen Namen mit einem der using Namespaces vor, um zu sehen, ob wir einen gültigen Typ erhalten.

Welcher Ansatz wäre besser, und was sind die Vor- und Nachteile?

Es ist im Moment unklar, wie viele Typen auf diese Weise für jeden Lauf gelöst werden müssen, aber ich nehme zwischen 10 und 100 an. Mehrere Baugruppen können an jedem Punkt referenziert werden, jeder mit möglicherweise hunderten von Typen .

Ich interessiere mich dafür, die relativen Leistungen beider Strategien zu kennen und neugierig zu sein, um Best Practices für dieses Szenario zu erfahren. Neben der Leistung wäre es sehr hilfreich, jeden Unterschied in den Nebeneffekten des Verhaltens zu verstehen: Werden beispielsweise alle Typen in einem Assembly alle statischen Konstruktoren für geladene Typen ausgeführt? Ich würde einen Ansatz bevorzugen, der beim Ausführen von Code von referenzierten Assemblys so faul wie möglich ist.

+0

ich glaube, dass dies ein [XY Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy (Problem) Es wäre nützlicher, wenn Sie erklären würden, was Sie versuchen erreiche damit, denn vielleicht versuchst du das Quadratrad neu zu erfinden. Oder wer weiß. Sagen Sie uns, welches die Voraussetzung für Ihr Problem ist. –

+0

@ MatíasFidemraizer Ich erwäge dynamische Auflösung Strategien für eine Skriptsprache und wäre gerne mit möglichen Strategien zur Zuordnung von Namen zu Typen und deren Auswirkungen. Auf keinen Fall wollte ich andeuten, dass ich eine Lösung für das Problem hatte, aber ich wollte die Ansätze auflisten, die mir in den Sinn kamen. Wäre toll, von irgendwelchen anderen Möglichkeiten zu erfahren. – glopes

+0

Erstellen Sie eine Skriptsprache? –

Antwort

0

Im neuen .NET-Standard stellt sich heraus, dass es einen viel besseren Weg gibt, den neuen Namespace System.Reflection.Metadata zu verwenden. In ihren eigenen Worten:

"Diese Pakete bietet eine Low-Level-.NET (ECMA-335) Metadaten-Reader.

Es ist für Performance ausgerichtet ist und ist die ideale Wahl geordnete Bibliotheken für den Aufbau, die ihr eigenes Objektmodell für die Auflistung der Namen, wie Compiler.“

Hier ist ein kleiner Code-Schnipsel zu schaffen beabsichtigen und Namensraum für alle Typdefinitionen in einer bestimmten Baugruppendatei:

using System; 
using System.IO; 
using System.Reflection.Metadata; 
using System.Reflection.PortableExecutable; 

namespace MetadataTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (var stream = File.OpenRead(args[0])) 
      using (var peFile = new PEReader(stream)) 
      { 
       var metadataReader = peFile.GetMetadataReader(); 
       foreach (var type in metadataReader.TypeDefinitions) 
       { 
        var definition = metadataReader.GetTypeDefinition(type); 
        var name = metadataReader.GetString(definition.Name); 
        var ns = metadataReader.GetString(definition.Namespace); 
        Console.WriteLine(ns + "." + name); 
       } 
      } 
     } 
    } 
} 
Verwandte Themen