Dieser Artikel wurde maschinell übersetzt.

Programmiererpraxis

Multiparadigmatisches .NET, Teil 5: Automatische Metaprogrammierung

Ted Neward

Des letzten Monats Stück Objekte geliefert wurde, unter die Lupe und insbesondere wir “ Achse ” Gemeinsamkeit/Variabilität Analyse, die Vererbung uns bietet haben. Während der Vererbung nicht die einzige Form der Gemeinsamkeiten/Streuung innerhalb einer modernen objektorientierten (OO) Sprache wie c# oder Visual Basic verfügbar ist, steht es sicherlich in der Mitte des OO-Paradigma. Und wie auch erwähnt, ist es immer die beste Lösung für alle Probleme bieten.

Um recap, was wir bisher festgestellt haben besteht darin, dass C#- und Visual Basic sowohl die Prozedural OO-Sprachen – aber deutlich die Fotostory nicht vorhanden. Beide sind auch metaprogrammatic Sprachen – jeweils bietet dem Microsoft .NET Framework-Entwickler die Möglichkeit, Programme außerhalb von Programmen, auf verschiedene Arten erstellen: Automatische reflektierend und generative.

Automatische Metaprogrammierung

Die grundlegende Idee metaprogramming Behind ist einfach: die herkömmlichen Konstrukte Prozedural oder OO-Programmierung noch nicht ganz alle unsere Software Entwurfsaspekte, zumindest nicht in einer Weise gelöst, die wir befriedigend finden. Um eine grundlegende Schwachstelle zu zitieren gefunden Entwickler beispielsweise häufig benötigt eine Datenstruktur, die eine geordnete Liste von einem bestimmten Typ, verwaltet, so dass wir fügen ein Element in der Liste in einem bestimmten Steckplatz und die Elemente in der genauen Reihenfolge anzeigen konnte. Aus Leistungsgründen wollte manchmal die Liste in einer verknüpften Liste von Knoten sein. Mit anderen Worten, wir wollten eine sortierte Liste für die verknüpfte, aber in den darin gespeicherten Typ stark typisiert.

Entwickler, die die C++-Welt auf .NET Framework stammt kennen, eine Lösung für dieses Problem –, die parametrisierte Typen auch mehr informell als Generika bezeichnet. Aber als Entwickler, die zu .NET über Java sind die Anfangszeiten kennen, eine andere Lösung Niveaus Vorlagen ergeben haben (was schließlich darauf in der Java-Plattform vorgenommen haben,). Diese Lösung wurde jede Implementierung erforderliche Liste ggf. einfach zu schreiben, wie in der Abbildung 1 .

Abbildung 1 ein Beispiel für das Schreiben von List-Implementierungen als erforderliche

Class ListOfInt32
  Class Node
    Public Sub New(ByVal dt As Int32)
      data = dt
    End Sub
    Public data As Int32
    Public nextNode As Node = Nothing
  End Class
  Private head As Node = Nothing
  Public Sub Insert(ByVal newParam As Int32)
    If IsNothing(head) Then
      head = New Node(newParam)
    Else
      Dim current As Node = head
      While (Not IsNothing(current.nextNode))
        current = current.nextNode
      End While
        current.nextNode = New Node(newParam)
    End If
  End Sub
  Public Function Retrieve(ByVal index As Int32)
    Dim current As Node = head
    Dim counter = 0
    While (Not IsNothing(current.nextNode) And counter < index)
      current = current.nextNode
      counter = counter + 1
    End While
    If (IsNothing(current)) Then
      Throw New Exception("Bad index")
    Else
      Retrieve = current.data
    End If
  End Function
End Class

Natürlich schlägt dies jetzt fehl Don't Wiederholen sich (trocken) – jedes Mal, wenn der Entwurf für eine neue Liste dieser Art aufruft, es wird “ von hand, ” geschrieben werden müssen, wird im Verlauf der Zeit deutlich ein Problem darstellen. Obwohl nicht kompliziert, soll es weiterhin unhandlich und jede dieser, insbesondere schreiben, wenn mehr Features erwünscht oder erforderlich sind zeitaufwändig sein.

Natürlich gesagt niemand jemals Entwicklern das Schreiben von Code werden mussten. Das bringt uns um ordentlich zur Lösung der Codegenerierung oder wie Sie hat bezeichnet, Automatische metaprogramming-. Ein anderes Programm möglich problemlos, wie z. B. ein Programm, das außerhalb von Klassen ausgelöst, die für jeden Typ benötigt, angepasst werden, wie in der Abbildung 2 .

Abbildung 2 ein Beispiel für die automatische Metaprogramming

Sub Main(ByVal args As String())
  Dim CRLF As String = Chr(13).ToString + Chr(10).ToString()
  Dim template As String =
   "Class ListOf{0}" + CRLF +
   "  Class Node" + CRLF +
   "    Public Sub New(ByVal dt As {0})" + CRLF +
   "      data = dt" + CRLF +
   "    End Sub" + CRLF +
   "    Public data As {0}" + CRLF +
   "    Public nextNode As Node = Nothing" + CRLF +
   "  End Class" + CRLF +
   "  Private head As Node = Nothing" + CRLF +
   "  Public Sub Insert(ByVal newParam As {0})" + CRLF +
   "    If IsNothing(head) Then" + CRLF +
   "      head = New Node(newParam)" + CRLF +
   "    Else" + CRLF +
   "      Dim current As Node = head" + CRLF +
   "      While (Not IsNothing(current.nextNode))" + CRLF +
   "        current = current.nextNode" + CRLF +
   "      End While" + CRLF +
   "      current.nextNode = New Node(newParam)" + CRLF +
   "    End If" + CRLF +
   "  End Sub" + CRLF +
   "  Public Function Retrieve(ByVal index As Int32)" + CRLF +
   "    Dim current As Node = head" + CRLF +
   "    Dim counter = 0" + CRLF +
   "    While (Not IsNothing(current.nextNode) And counter < index)"+ CRLF +
   "      current = current.nextNode" + CRLF +
   "      counter = counter + 1" + CRLF +
   "    End While" + CRLF +
   "    If (IsNothing(current)) Then" + CRLF +
   "      Throw New Exception()" + CRLF +
   "    Else" + CRLF +
   "      Retrieve = current.data" + CRLF +
   "    End If" + CRLF +
   "  End Sub" + CRLF +
   "End Class"
    If args.Length = 0 Then
      Console.WriteLine("Usage: VBAuto <listType>")
      Console.WriteLine("   where <listType> is a fully-qualified CLR typename")
    Else
      Console.WriteLine("Producing ListOf" + args(0))
      Dim outType As System.Type =
        System.Reflection.Assembly.Load("mscorlib").GetType(args(0))
      Using out As New StreamWriter(New FileStream("ListOf" + outType.Name + ".vb",
                                              FileMode.Create))
        out.WriteLine(template, outType.Name)
      End Using
    End If

Dann nach die betreffenden Klasse erstellt wurde, muss nur kompiliert werden und entweder dem Projekt hinzugefügt, sonst in einer eigenen Assembly zur Wiederverwendung als eine Binärdatei kompiliert.

Natürlich keinen generierte Sprache werden die Sprache, in der Code-Generator erstellt wird, wird in der Tat häufig äußerst Hilfe Wenn nicht, da dann einfacher zu die beiden während des Debuggens im Kopf des Entwicklers deutlich unterschiedliche beibehalten werden.

Gemeinsamkeit, Variabilität und Vorteile und Nachteile

Bei der Analyse Gemeinsamkeit/Variabilität belegt metaprogramming automatisch eine interessante Stelle. Im Beispiel Abbildung 2 speichert Struktur und Verhalten (die Gliederung der obigen Klasse) in Gemeinsamkeit, Variabilität an Datentyp/Linien, ermöglicht, den Typ, der in der generierten Klasse gespeichert werden. Natürlich können wir in beliebigen Typs in den Typ ListOf gewünscht vertauschen.

Aber automatische metaprogramming kann stornieren, deren, auch bei Bedarf. Verwenden eine umfangreiche Vorlagenerstellung Sprache, wie z. B. dem Text Vorlage Transformation Toolkit (T4), die mit Visual Studio die Codegenerierung Vorlagen ausgeliefert wird Quelle Zeit Entscheidungsfindung durchführen können, können dann die Vorlage an Daten/strukturelle Linien Gemeinsamkeit bereitstellen und variieren je nach strukturelle und geänderten Zeilen. In der Tat ist wenn die Codevorlage ausreichend komplex ist (und dies ist nicht unbedingt um einen guten Winkel, fortzusetzen), es sogar möglich, Gemeinsamkeit komplett zu entfernen und alle Daten (Daten, Struktur, Verhalten und So weiter) variieren. Dieser Vorgang sollte daher normalerweise nicht verwaltbar ziemlich schnell wird jedoch und im Allgemeinen vermieden werden. Führt zu einem der wichtigsten Realizations über automatische metaprogramming: Weil jede Art von inhärente Struktur Einschränkungen fehlt, wählen Sie die Gemeinsamkeiten und der Streuung explizit, damit die Source Codevorlage wachsen außerhalb des Steuerelements zu flexibel sein möchten. Beispielsweise angegebenen Beispiel ListOf in Abbildung 2 , die Gemeinsamkeit ist in die Struktur und das Verhalten und die Streuung in den gespeicherten Datentyp ist – Einführung der Streuung in die Struktur oder das Verhalten bei dem Versuch sollte ein rotes Kennzeichen und einen potenziellen Slippery Steigung um Chaos berücksichtigt werden.

Natürlich führt Codegenerierung mit einigen signifikanten Risiken, insbesondere um Bereiche der Wartung: (Z. B. die Parallelität eine im Beispiel ListOf… in Abbildung 2 ) ein Fehler erkannt werden soll, korrigiert es nicht einfach. Die Vorlage kann natürlich behoben, aber, das nicht tun, was für bereits generierten Code – jede von dieser Quelle Artefakte muss wiederum generiert werden, und dies ist etwas, das schwer zu verfolgen und wird automatisch sichergestellt ist. Und was ’s mehr handmade Änderungen auf die generierten Dateien verloren systemintern, sofern der Vorlage generiert Code für die Anpassungen zugelassen wurde. Dieses Risiko überschreiben kann verringert werden, mithilfe der partielle Klassen, sodass Entwickler die “ andere Hälfte ” (oder nicht) Ausfüllen der generierten Klasse und Erweiterungsmethoden, bieten Entwicklern die Möglichkeit, “ Methoden zu einer vorhandenen Familie von Typen hinzufügen ” ohne die Typen zu bearbeiten. Aber partielle Klassen müssen direkt vom Anfang innerhalb der Dokumentvorlagen und Erweiterungsmethoden führen einige Einschränkungen, die nicht ersetzt bestehende Verhalten – lassen weder Ansatz erneut als Mechanismus, negative Variabilität ausführen können.

Codeerzeugung

Codegenerierung – oder automatisch metaprogramming – ist eine Technik, die Teil bereits seit vielen Jahren programmieren, C Präprozessormakro über c# T4-Engine ganz angefangen wurde, und wird wahrscheinlich weiter nach vorne, was die begriffliche Einfachheit des die Idee führen. Die wichtigsten Sicherheitslücken sind jedoch das Fehlen der Compiler Struktur und Überprüfung während der Erweiterung (sofern natürlich, dass Überprüfung vom Code-Generator selbst eine Aufgabe ausgeführt wird, die schwieriger als es klingt) sowie die Unfähigkeit, negative Variabilität auf sinnvolle Weise zu erfassen. .NET Framework bietet einige Mechanismen zum Generieren von Code zu erleichtern, in vielen Fällen wurden diese Mechanismen eingeführt, um andere Entwickler Microsoft einige Grief speichern –, aber Sie wird nicht alle möglichen Fehlerquellen in Codegenerierung nicht durch eine lange Schlag beseitigen.

Und noch, automatische metaprogramming bleibt eine der Formen der mehr weit verbreiteten metaprogramming. C# hat ein Makro Präprozessor, wie C++- und c. (Verwenden von Makros zum Erstellen von “ winziger Vorlagen ” wurde häufig vor C++ Vorlagen haben.) Oben in diesem, Verwendung metaprogramming als Teil eines größeren Framework oder Bibliothek sehr häufig, besonders für die prozessübergreifende Kommunikationsszenarios (z. B. die Client- und Server-Stubs von Windows Communication Foundation generierte) ist. Andere Toolkits Verwendung automatischer metaprogramming “ Gerüstbau ” zu erleichtern, die frühen Phasen einer Anwendung (z. B. was wir in ASP.NET MVC sehen). In der Tat wohl alle Visual Studio-Projekt beginnt mit automatischer metaprogramming, in Form von “ Projektvorlagen ” und “ Elementvorlagen ”, die meisten von uns zu verwenden, erstellen Sie neue Projekte oder Hinzufügen von Dateien zu Projekten. Und so weiter. Wie viele andere Dinge in Informatik bleibt metaprogramming automatisch ein nützliches und praktisches Tool in der Designer-Toolbox Trotz seiner offensichtliche Mängel und mögliche Fehlerquellen verfügen. Glücklicherweise ist es alles andere als einzige Meta-Tool in der Toolbox des Programmierers.

Ted Neward ist ein Geschäftsführer von Neward & Associates, einer unabhängigen Firma, die sich auf .NET Framework- und Java-Plattformsysteme für Unternehmen spezialisiert hat. Er hat mehr als 100 Artikel geschrieben, wird ein C#-MVP und INETA-Sprecher und hat verfasst und Mitverfasser von einem Dutzend Bücher, unter anderem “ Professional f# 2.0 ” (Wrox 2010). Er wird auch konsultiert und regelmäßig mentors. Sie können ihn unter ted@tedneward.com erreichen, oder lesen Sie seinen Blog unter blogs.tedneward.com.