Il s'agit de la dernière partie de la série
Dynamic Language Runtime . Articles précédents:
- Détail dynamique: jeux d'infiltration du compilateur, fuite de mémoire, nuances de performances . Cet article décrit le cache DLR en détail et les points importants pour le développeur.
- Grokl DLR . Un aperçu général de la technologie, la dissection de DynamicMetaObject et une brève instruction sur la façon de créer votre propre classe dynamique.
Dans ce court article, nous analyserons enfin les principaux cas d'utilisation de la
dynamique dans la vie réelle: quand on ne peut plus s'en passer et quand cela peut grandement faciliter l'existence.

Quand la dynamique est indispensable
Il n'y a pas de tels cas. Vous pouvez toujours écrire du code de fonctionnalité similaire dans un style statique, la seule différence est la facilité de lecture et la quantité de code. Par exemple, lorsque vous travaillez avec des objets COM, au lieu de
dynamiques, vous pouvez utiliser la réflexion.
Quand la dynamique est utile
Travailler avec des objets COM
Tout d'abord, bien sûr, c'est un travail avec des objets COM, pour le plaisir de commencer. Comparez le code obtenu avec
dynamique et réflexion:
dynamic instance = Activator.CreateInstance(type); instance.Run("Notepad.exe");
var instance = Activator.CreateInstance(type); type.InvokeMember("Run", BindingFlags.InvokeMethod, null, instance, new[] { "Notepad.exe" });
En règle générale, pour travailler avec des objets COM par réflexion, vous devez créer des classes branchées avec des wrappers pour chaque méthode / propriété. Il existe également des avantages moins évidents tels que la possibilité de ne pas remplir les paramètres dont vous n'avez pas besoin (obligatoire du point de vue d'un objet COM) lors de l'appel d'une méthode via
Dynamic .
Travailler avec des configurations
Un autre exemple de manuel fonctionne avec des configurations, telles que
XML . Sans
dynamique :
XElement person = XElement.Parse(xml); Console.WriteLine( $"{person.Descendants("FirstName").FirstOrDefault().Value} {person.Descendants("LastName").FirstOrDefault().Value}" );
Avec dynamique:
dynamic person = DynamicXml.Parse(xml); Console.WriteLine( $"{person.FirstName} {person.LastName}" );
Bien sûr, pour cela, vous devez implémenter votre propre classe dynamique. Comme alternative à la première liste, vous pouvez écrire une classe qui fonctionnera comme ceci:
var person = StaticXml.Parse(xml); Console.WriteLine( $"{person.GetElement("FirstName")} {person.GetElement("LastName")}" );
Mais, vous voyez, cela semble beaucoup moins élégant que
dynamique .
Travailler avec des ressources externes
Le paragraphe précédent peut être généralisé à toutes les actions avec des ressources externes. Nous avons toujours deux alternatives: utiliser
dynamique pour obtenir le code en style C # natif ou taper statique avec des «lignes magiques». Regardons un exemple avec une demande d'
API REST . Avec dynamic, vous pouvez écrire ceci:
dynamic dynamicRestApiClient = new DynamicRestApiClient("http://localhost:18457/api"); dynamic catsList = dynamicRestApiClient.CatsList;
Où notre classe dynamique enverra une demande de formulaire à la demande de la propriété
[GET] http://localhost:18457/api/catslist
Puis il le désérialise et nous retourne un ensemble de chats déjà prêts pour l'usage prévu. Sans
dynamique, cela ressemblerait à ceci:
var restApiClient = new RestApiClient("http://localhost:18457/api"); var catsListJson = restApiClient.Get("catsList"); var deserializedCatsList = JsonConvert.DeserializeObject<Cat[]>(catsListJson);
Remplacement de la réflexion
Dans l'exemple précédent, vous pourriez avoir la question: pourquoi dans un cas, nous désérialisons la valeur de retour en un type spécifique, et dans l'autre non? Le fait est que dans le typage statique, nous devons explicitement convertir des objets en type
Cat pour travailler avec eux. Dans le cas de la
dynamique , il suffit de désérialiser
JSON en un tableau d'objets à l'intérieur de notre classe dynamique et d'en renvoyer l'
objet [] , car la
dynamique prend soin de la réflexion. Je vais donner deux exemples de comment cela fonctionne:
dynamic deserialized = JsonConvert.DeserializeObject<object>(serialized); var name = deserialized.Name; var lastName = deserialized.LastName;
Attribute[] attributes = type.GetCustomAttributes(false).OfType<Attribute>(); dynamic attribute = attributes.Single(x => x.GetType().Name == "DescriptionAttribute"); var description = attribute.Description;
Le même principe que lorsque vous travaillez avec des objets COM.
Visiteur
En utilisant
dynamique, vous pouvez implémenter ce modèle de manière très élégante. Au lieu de mille mots:
public static void DoSomeWork(Item item) { InternalDoSomeWork((dynamic) item); } private static void InternalDoSomeWork(Item item) { throw new Exception("Couldn't find handler for " + item.GetType()); } private static void InternalDoSomeWork(Sword item) {
Désormais, lors du passage d'un objet de type
Sword à la méthode
DoSomeWork , la méthode
InternalDoSomeWork (élément Sword) sera appelée.
Conclusions
Avantages de l'utilisation
dynamique :
- Peut être utilisé pour le prototypage rapide: dans la plupart des cas, le nombre de codes passe-partout diminue
- En règle générale, il améliore la lisibilité et l'esthétique (en raison de la transition des «lignes magiques» au style natif de la langue) du code
- Malgré l'opinion répandue, grâce aux mécanismes de mise en cache, un surdébit de performances significatif dans le cas général ne se pose pas
Inconvénients de l'utilisation dynamique:
- Il existe des nuances évidentes associées à la mémoire et aux performances.
- Avec le soutien et la lecture de ces classes dynamiques, vous devez bien comprendre ce qui se passe
- Le programmeur est privé de vérification de type et de toutes les garanties de santé fournies par le compilateur
Conclusion
À mon avis, le développeur tirera le plus grand profit de l'utilisation de Dynamic dans les situations suivantes:
- Lors du prototypage
- Dans les petits projets / projets à domicile où le coût d'erreur est faible
- Dans les petits utilitaires de taille de code qui n'impliquent pas une longue durée. Si votre utilitaire s'exécute dans le pire des cas pendant quelques secondes, il n'est généralement pas nécessaire de penser aux fuites de mémoire et à la dégradation des performances
Au moins controversé est l'utilisation de la
dynamique dans des projets complexes avec une grande base de code - ici, il est préférable de passer du temps à écrire des wrappers statiques, minimisant ainsi le nombre de moments non évidents.
Si vous travaillez avec des objets ou des domaines COM dans des services / produits qui impliquent un long temps de travail continu, il est préférable de ne pas utiliser
dynamique , malgré le fait qu'il a été créé pour de tels cas. Même si vous savez parfaitement quoi et comment faire et ne faites jamais d'erreurs, tôt ou tard un nouveau développeur peut arriver qui ne le sait pas. Le résultat est probablement une fuite de mémoire difficile à calculer.