Downcasting d'objet en C#

Il peut parfois s'avérer utile, notamment lorsque l'on souhaite ajouter une propriété à une classe, d'utiliser le downcasting, malheureusement celui-ci n'est pas autorisé en .NET, la compilation sera faite mais une exception de type System.InvalidCastException sera générée à l'exécution. Le mécanisme d'extension de classes ne peut être utilisé ici et si la classe à étendre n'est pas partial, il ne reste plus que le mécanisme de l'héritage. Or parfois l'on se retrouve avec un ensemble d'objets déjà définis, objets que l'on a étendu à l'aide de l'héritage. Il faudrait donc arrivé à effectuer un cast de ces objets ClassBase en ClassDerived

idéalement

ClassDerived derivedObject = (ClassDerived)baseObject;

mais .NET ne le permet pas, on ne peut caster en effet que du sens enfant vers parent

ClassBase baseObject = (ClassBase)derivedObject;

Ceci se comprend aisément puisque effectuer un cast dans le sens parent vers enfant reviendrait à dire que toutes les propriétés ajoutées à l'enfant ne peuvent pas être initialisées avec une valeur provenant du parent puisqu'il n'en a aucune connaissance. Pourtant la création d'un objet dérivé va initialiser les valeurs de ces propriétés à leur valeur par défaut, on peut donc utiliser ce mécanisme pour "caster" l'objet parent en enfant.
En effet la technique va consister à créer un objet enfant puis à recopier toutes les valeurs des propriétés de l'objet parent, qui se trouvent dans l'objet enfant puisque celui-ci hérite de l'objet parent, dans les propriétés de l'objet enfant puis à renvoyer ce nouvel objet créé.
Pour réaliser cela, je vous propose une classe statique helper contenant la fonction de downcasting en générique.


using System.Collections.Generic;
using System.Reflection;

public static class GenericHelper
{
    /// <summary>
    /// Convertir un objet TFrom en TTo, TTo héritant de TFrom
    /// </summary>
    /// <example>
    /// Appel à la fonction
    /// <code>
    /// GenericHelper.DownCastingObject<TypeCible, TypeSource>(objetSource)
    /// </code>
    /// </example>
    /// <typeparam name="TTo">
    /// <c>Type</c> cible de la conversion
    /// </typeparam>
    /// <typeparam name="TFrom">
    /// <c>Type</c> source de la conversion
    /// </typeparam>
    /// <param name="data">
    /// Objet à convertir
    /// </param>
    /// <returns>
    /// Un nouvel objet TTo
    /// </returns>
    public static TTo DownCastingObject<TTo, TFrom> (TFrom data) where TTo : TFrom, new()
    {
        var objet = new TTo();
        foreach (PropertyInfo prop in typeof(TFrom).GetProperties())
        {
            objet.GetType().GetProperty(prop.Name).SetValue(objet, prop.GetValue(data, null), null);
        }
        return objet;
    }

    /// <summary>
    /// Convertir une List<TFrom> en List<TTo>, TTo héritant de TFrom
    /// </summary>
    /// <example>
    /// Appel à la fonction
    /// <code>
    /// GenericHelper.ConvertListTo<TypeCible, TypeSource>(listeDonnees)
    /// </code>
    /// </example>
    /// <typeparam name="TTo">
    /// <c>Type</c> cible de la conversion
    /// </typeparam>
    /// <typeparam name="TFrom">
    /// <c>Type</c> source de la conversion
    /// </typeparam>
    /// <param name="datas">
    /// Données à convertir
    /// </param>
    /// <returns>
    /// Une nouvelle List<TTo>
    /// </returns>
    public static List<TTo> ConvertListTo<TTo, TFrom>(List<TFrom> datas) where TTo : TFrom, new()
    {
        var list = new List<TTo>();
        if(typeof(TTo).BaseType == typeof(TFrom))
        {
            foreach (var data in datas)
            {                    
                var o = (TTo)DownCastingObject<TTo, TFrom>(data);
                list.Add(o);
            }
        }
        return list;
    }
}

Le downcasting s’effectue donc de la façon suivante


var baseObject = new ClassBase
            {
                Libelle = "Classe de base"
            };

var derivedObject = GenericHelper.DownCastingObject<ClassDerived, ClassBase>(baseObject);

Le helper contient également une fonction de conversion d’une List<> d’objets de base en une List<> d’objets dérivés, à utiliser de la façon suivante


var listDerived = GenericHelper.ConvertListTo<ClassDerived, ClassBase>(listBase);

L'ensemble des sources est à retrouver sur mon skydrive



// coding with fun

Écrire un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec une *

Quelle est la première lettre du mot oikx ? :