Créer une simple classe immuable en C# est facile. Il vous suffit de créer un constructeur et de ne pas parvenir à créer des setters publics. Mais souvent cela ne suffit pas. Finalement, vous pouvez vouloir créer des graphes profonds qui, pour des raisons d'efficacité, devraient être créés via un constructeur. Ou peut-être que vous voulez faire des mises à jour non destructives en créant des méthodes qui renvoient une copie de l'objet avec un champ modifié (par exemple, la méthode AddMinutes sur DateTime). Construire tous ces constructeurs et ces méthodes peut être assez fastidieux et donc sujet aux erreurs.
Andrew L. Arnott a une solution qui s'appuie sur des générateurs de code à base de T4. T4, si vous n'êtes pas familier avec ceci, est synonyme de Toolkit de Transformation de Templates de Texte. Cette question est au cœur des capacités de génération de code de Visual Studio et les bibliothèques comme Entity Framework comptent sur elle. Les scripts T4 prennent une classe mutable et créent un clone immuable.
Le toolkit d’Andrew prend une décision quelque peu controversée de ne pas créer de constructeurs publics. Au lieu de cela vous êtes censé utiliser une méthode statique Create ou de commencer par l'instance par défaut et de la modifier à partir de là. Ceci est fait en utilisant les méthodes WithXxx, pour lesquelles il en existe une par propriété.
Nous pouvons faire encore quelques améliorations cependant. Pour les classes avec de nombreuses propriétés, si vous avez besoin de modifier plusieurs propriétés à la fois, allouer un nouvel objet à chaque changement de propriétés comme une étape intermédiaire est inutile et peut contribuer à un GC trop présent. Donc, nous ajoutons également une méthode With qui prend des paramètres facultatifs pour toutes les propriétés trouvées sur la classe, permettant des changements de propriétés en vrac. Enfin, pour les scénarios où vous avez plusieurs modifications à apporter à l'objet, mais souhaitez les faire dans un mode multi-étapes (ou tout simplement préférer les setters de propriétés aux méthodes With), nous pouvons construire une classe Builder qui permet la mutation, et peut ensuite retourner la copie immuable lorsque vous avez terminé. Ce modèle est très similaire à String et StringBuilder dans le framework .NET, et aussi comme les dernières collections immuables mentionnées plus tôt.
Bien sûr, si vous n'aimez pas ces décisions, vous pouvez facilement modifier les templates T4. Andrew a délibérément séparé les templates dans des fichiers plus petits pour faciliter cette opération. Vous pouvez également ajouter vos propres extensions sans modifier sensiblement les templates de base.
Comme tous les générateurs de code bien écrits, celui-ci utilise largement des méthodes partielles. Les méthodes partielles permettent aux développeurs d'injecter une logique supplémentaire sur les méthodes du code généré sans avoir à modifier le fichier généré. Par exemple, on peut mettre en œuvre une méthode pour définir les valeurs partielles par défaut pour l'objet immuable. Les méthodes partielles qui ne sont pas mises en œuvre seront supprimées automatiquement par le compilateur, ne générant donc pas de coût d'exécution.
Vous pouvez en savoir plus sur les expériences de Arnott avec les graphes d'objets immuables sur son blog.