Este artigo foi traduzido por máquina.

Le programmeur au travail

.NET multiparadigmatique, partie 5 : Métaprogrammation automatique

Ted Neward

Dans le mois dernier de la pièce , objets fournie au microscope et en particulier, nous avons examiné le “ axe ” d'analyse uniformité/variabilité que l'héritage propose de nous. Pendant que l'héritage n'est pas la seule forme d'uniformité/variabilité disponible au sein d'une langue (OO) moderne orientés objet tels que c# ou Visual Basic, il est certainement l'abréviation au centre du paradigme OO. Et, comme nous l'avons également vu, il n'est pas toujours fournir la meilleure solution à tous les problèmes.

En résumé, ce que nous avons découvert jusqu'ici est que c# et Visual Basic sont des procédures et des langues OO — mais clairement l'histoire n'est pas arrête là. Les deux sont également metaprogrammatic langues, chacun offre au développeur Microsoft .NET Framework la possibilité de créer des programmes de programmes, de plusieurs façons différentes : automatique, Réflectif et GENERATRICE.

Métaprogrammation automatique

L'idée principale behind metaprogramming est simple : les constructions de procédure ou de programmation OO traditionnelles n'ont pas résolu assez toutes nos problèmes de conception logicielle au moins pas d'une façon qui nous trouvons satisfaisantes. Par exemple, pour citer un défaut de base, les développeurs trouvé fréquemment besoin d'une structure de données mis à jour une liste ordonnée d'un type particulier, par exemple où nous pouvons insérer des éléments dans la liste dans un emplacement particulier et consultez les articles dans l'ordre exact. Pour des raisons de performances, parfois la liste voulu se trouver dans une liste liée de nœuds. En d'autres termes, nous voulu une liste liée, mais fortement typées pour le type qui est stocké dans il.

Les développeurs qui fournie pour le .NET Framework à partir de l'univers C++ savent l'une des solutions à ce problème : celle des types paramétrés, également appelées de manière plus informelle comme des génériques. Mais, en tant que développeurs, qui se sont vers .NET à Java de débuts savoir, une autre solution est né bien avant les modèles (qui est le cas, le faire par la suite, à la plate-forme Java). Cette solution a été simplement écrire chaque implémentation de la liste nécessaire selon vos besoins, comme dans de la figure 1 .

Figure 1 un exemple d'écriture mises en œuvre de la liste en tant que nécessaire,

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

À présent, évidemment, ceci fait échouer le test de pas répéter vous-même (sec) — chaque fois que la conception requiert une nouvelle liste de ce type, vous devrez écrire “ à la main, ” qui sera bien un problème au cours du temps. Bien que ne pas compliqué, il sera toujours maladroite et prendre du temps à écrire chacun de ces éléments, particulièrement si davantage de fonctionnalités devenue nécessaires ou souhaitables.

Bien sûr, personne n'a jamais les développeurs devaient être ceux écrire un tel code. Qui nous amène soigneusement à la solution de génération de code, ou qu'elle a parfois appelée, automatique metaprogramming de . Un autre programme peut facilement faire, tel qu'un programme conçu pour les classes qui sont personnalisées pour chaque type requis, comme dans de la figure 2 .

La figure 2 exemple automatique 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

Ensuite, une fois que la classe en question a été créée, il ne doit être compilé et soit ajouté au projet ou bien compilé dans son propre assembly pour une réutilisation en tant qu'un fichier binaire.

Bien sûr, le langage en cours de génération n'a pas à la langue dans laquelle le Générateur de code est écrit, en fait, il vous sera souvent utile considérablement si non, parce que, puis il sera plus facile de conserver les deux plus clairement distinct en tête du développeur au cours du débogage.

Composants communs, variabilité et les professionnels de l'op

Dans l'analyse uniformité/variabilité, automatique metaprogramming tient une place intéressante. Dans l'exemple de figure 2, il place structure et le comportement (le contour de la classe ci-dessus) à compatibilité ascendante et descendante, ce qui permet de variabilité le long de lignes/type de données, celui du type qui est stocké dans la classe générée. À l'évidence, nous pouvons changer dans n'importe quel type de leur choix dans le type de ListOf.

Mais automatique metaprogramming pouvez contrepasser que, trop, si nécessaire. En utilisant un langage de création de modèles de riches, telles que la boîte à outils de transformation du modèle de texte (T4) est fourni avec Visual Studio, la génération de code modèles faire prise de décision de source de temps, qui permet ensuite le modèle pour fournir des composants communs en même temps que les lignes de données/structurelle et varient selon les lignes structurelles et comportement. En fait, si le modèle de code est suffisamment complexe (et cela n'est pas nécessairement un angle de bon poursuivre), il est même possible d'éliminer complètement les composants communs et de varier de tous les éléments (données, structure, comportement et ainsi de suite). Cette procédure généralement devient ingérable assez rapidement, cependant et il est en général être évitée. Qui conduit à l'un des clé realizations sur automatique metaprogramming : Dans la mesure où il ne dispose pas de type quelconque de restrictions de structurels inhérentes, choisissez la compatibilité ascendante et descendante et la dispersion explicitement, moins le modèle de code source de croissance du contrôle de tenter d'être trop souple. Par exemple, étant donné l'exemple ListOf dans de la figure 2 , la compatibilité ascendante et descendante est dans la structure et le comportement et la variabilité est dans le type de données qui sont stocké, si vous tentez de les introduire de variabilité dans la structure ou un comportement doit être considéré comme un indicateur rouge et une pente slippery potentielle au chaos.

Évidemment, la génération de code exécute avec lui quelques risques importants, en particulier autour des zones de maintenance : Un bogue doit être découverts (par exemple, la concurrence d'accès un dans l'exemple ListOf… dans de la figure 2 ), résoudre n'est pas une question simple. Le modèle peut évidemment être corrigé, mais qui ne fait rien pour le code déjà généré : chacune de ces artefacts source doit être regénérés à son tour, et il s'agit d'un élément est difficile de contrôler et de garantir automatiquement. Et bien, que se passe-t-il ’s plus, toutes les modifications à ces fichiers générés fait main seront intrinsèquement perdues, à moins que le code généré par le modèle a autorisé pour les personnalisations. Ce risque de remplacement peut être atténué par l'utilisation des classes partielles, permettant ainsi aux développeurs remplir le “ autre moitié ” (ou pas) de la classe en cours de génération et par les méthodes d'extension, donnant aux développeurs une opportunité “ ajouter ” des méthodes à une famille de types existante sans avoir à modifier les types. Mais les classes partielles doivent être installés à partir du début dans les modèles et méthodes d'extension effectuer quelques restrictions qui les empêchent de remplacer le comportement existant, à nouveau avec aucune approche comme un bon mécanisme pour effectuer la variabilité négative.

Génération de code

Génération de code — ou automatique metaprogramming — est une technique qui a été une partie de la programmation de nombreuses années, complètement allant de la macro de préprocesseur C par l'intermédiaire du moteur de langage c# T4 et continue probablement à reporter en raison de la simplicité de l'idée conceptuelle. Cependant, ses failles principales sont le manque de la structure du compilateur et la vérification pendant le processus d'extension (sauf, bien sûr, que le contrôle est effectué par le Générateur de code lui-même, une tâche qui est plus difficile qu'il n'y paraît) et l'incapacité à capturer variabilité négative d'une manière significative. Le .NET Framework propose certains mécanismes pour faciliter la génération de code — dans de nombreux cas, ces mécanismes ont été introduites pour enregistrer les autres développeurs Microsoft certains compliqué, mais ils ne sont pas éliminer tous les pièges potentiels dans génération de code, pas par une capture de longues.

Et pourtant, automatique metaprogramming reste l'une des formes plus largement utilisées de metaprogramming. C# possède une macro préprocesseur, comme C++ et c. (À l'aide de macros pour créer des “ petits modèles ” était courant avant de C++ a obtenu les modèles.) Utilisation de qui, outre metaprogramming comme partie d'un plus grand cadre ou bibliothèque est courant, en particulier pour les scénarios de communication interprocessus (tels que des stubs de client et serveur générés par Windows Communication Foundation). Autres kits de ressources utilisent automatique metaprogramming pour “ échafaudage ” pour faciliter les premières étapes d'une application (par exemple, nous voyons dans ASP.NET MVC). En fait, sans doute chaque projet Visual Studio commence par automatique metaprogramming, dans l'écran des “ modèles de projet ” et modèles d'élément “ ” que la plupart d'entre nous permet de créer de nouveaux projets ou ajouter des fichiers aux projets. Et ainsi de suite. Comme tant de choses en informatique, automatique metaprogramming reste un outil utile et pratique d'avoir dans la boîte à outils Concepteur, en dépit de son évidentes d'imperfections et les pièges à éviter. Heureusement, il est loin d'être le seul outil meta dans la boîte à outils du programmeur.

Ted Neward co-dirige Neward & Associates, une firme indépendante spécialisée dans les systèmes de plateforme d'entreprise .NET Framework et Java. Il a écrit plus de 100 articles, est un conférencier INETA et les MVP c# et a créé et signé par deux auteurs de livres d'une douzaine, notamment “ Professionnel F # 2.0 ” (Wrox, 2010). En outre, il consulte et mentors régulièrement. Vous pouvez le contacter à l'adresse ted@tedneward.com et consulter son blog sur blogs.tedneward.com.