How to dynamically add properties to an existing object – dynamic keyword trick
2012-05-28Les développeurs sont fainéants, c’est l’une de leurs nombreuses qualités…
To Wrap or not to wrap
Je travaille sur une bibliothèque .NET pour une api REST, dont un des objets modèle contient une propriété stockant l’url d’une image. Mon but est de sauvegarder cette image localement, puis d’ajouter le chemin local à l’objet, et enfin de sérialiser cet objet en json.
J’utilise pour ça Json.NET.
Je ne veux pas modifier directement le code de l’objet de l’api, même si ça serait sans doute la façon la plus simple de procéder, car ce que je veux faire commence à être trop éloigné du but du code de départ, et je veux garder les choses séparées.
Je pourrais créer une nouvelle classe reprenant toutes les propriétés de mon modèle et les recopier une à une, mais c’est fastidieux et inintéressant. Je peux aussi créer une classe héritant de mon objet et ajouter seulement ce dont j’ai besoin, mais comme je ne peux pas caster vers un objet plus dérivé, il faudrait là aussi que je réassigne toutes les propriétés à la main (et ça c’est pas possible si les setters sont privés).
Ca serait aussi appréciable si la solution pouvait être générique et facilement adaptable à un autre objet; recréer à chaque fois une classe destinée uniquement à la sérialisation n’est pas des plus productif (j’en ai assez fait en java pour être sur que ça ne me plait pas)…
La partie intéressante
Une solution vous vient peut être à l’idée : la réflexion, pour automatiquement cloner un objet et le peupler.
On en aura effectivement besoin, mais cette technique nécessite d’avoir un objet à peupler, et donc de devoir créer une nouvelle classe, servant je le rappelle uniquement comme étape pour la sérialisation. On peut mieux faire.
J’ai finalement creusé du coté du mot clé dynamic
de C# 4.0, que je n’avais encore quasiment pas eu l’occasion d’utiliser ; transformer un langage typé en une bouillie indébuggable ne faisant pas partie de mes grandes passions.
Il est possible avec un objet dynamic
, si on l’initialise avec un objet de type ExpandoObject
, de lui ajouter dynamiquement des propriétés.
Une autre fonction intéressante de l’ExpandoObject
est que l’on peut le caster en IDictionary<string, object>
, et qu’on peut ensuite lui ajouter une propriété via ce dictionnaire !
Sachant cela, il est assez facile d’en tirer la fonction suivante :
public dynamic CloneObject(object obj)
{
dynamic d = new System.Dynamic.ExpandoObject();
var typeofObject = obj.GetType();
var members = typeofObject.GetProperties();
var assignableD = (d as IDictionary<string, object>);
foreach (var property in members)
{
assignableD[property.Name] = property.GetValue(obj, null);
}
return d;
}
Qui permet facilement de sérialiser un objet en lui ajoutant ou en modifiant à la volée ses propriétés:
The comment is shown highlighted below in context.
JavaScript is required to see the comments. Sorry...