153 votes

Convertir la classe de base en classe dérivée

Est-il possible en C# de convertir explicitement un objet de classe de base en une de ses classes dérivées ? Actuellement, je pense que je dois créer un constructeur pour mes classes dérivées qui acceptent un objet de classe de base comme paramètre et copier les valeurs des propriétés. Je n'aime pas vraiment cette idée, et j'aimerais l'éviter si possible.

Cela ne semble pas devoir fonctionner (l'objet est instancié en tant que nouvelle base, donc la mémoire ne devrait pas être allouée pour les membres supplémentaires de la classe dérivée) mais le C# semble me permettre de le faire :

class BaseClass
{
  ... some stuff ...
}

class DerivedClass : BaseClass
{
    public bool MyDerivedProperty{ get; set; }
}

static void Main(string[] args)
{
    BaseClass myBaseObject = new BaseClass();
    DerivedClass myDerivedObject = myBaseObject as DerivedClass;

    myDerivedObject.MyDerivedProperty = true;
}

133voto

Tim S. Points 30377

Non, il n'y a pas de moyen intégré pour convertir une classe comme vous le dites. La façon la plus simple de le faire serait de faire ce que vous avez suggéré : créer une classe DerivedClass(BaseClass) constructeur. D'autres options permettraient essentiellement d'automatiser la copie des propriétés de la base vers l'instance dérivée, par exemple en utilisant la réflexion.

Le code que vous avez posté en utilisant as compilera, comme vous l'avez certainement constaté, mais lèvera une exception de référence nulle lorsque vous l'exécuterez, car myBaseObject as DerivedClass évaluera à null puisqu'il ne s'agit pas d'une instance de DerivedClass .

63voto

Mahmoodvcs Points 956

Vous pouvez utiliser un mappeur d'objets comme AutoMapper

Edit

Exemple :

class A
{
    public int IntProp { get; set; }
}
class B
{
    public int IntProp { get; set; }
    public string StrProp { get; set; }
}

Dans global.asax ou au démarrage de l'application :

AutoMapper.Mapper.CreateMap<A, B>();

Utilisation :

var b = AutoMapper.Mapper.Map<B>(a);

Il est facilement configurable via une API fluide.

15voto

meffect Points 431

J'ai trouvé une solution à ce problème, je ne dis pas que c'est la meilleure, mais elle me semble propre et ne nécessite pas de changements majeurs dans mon code. Mon code ressemblait au vôtre jusqu'à ce que je réalise qu'il ne fonctionnait pas.

Ma classe de base

public class MyBaseClass
{
   public string BaseProperty1 { get; set; }
   public string BaseProperty2 { get; set; }
   public string BaseProperty3 { get; set; }
   public string BaseProperty4 { get; set; }
   public string BaseProperty5 { get; set; }
}

Ma classe dérivée

public class MyDerivedClass : MyBaseClass
{
   public string DerivedProperty1 { get; set; }
   public string DerivedProperty2 { get; set; }
   public string DerivedProperty3 { get; set; }
}

Méthode précédente pour obtenir une classe de base peuplée

public MyBaseClass GetPopulatedBaseClass()
{
   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;
}

Avant, j'ai essayé ceci, qui m'a donné une erreur de type "unable to cast".

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

J'ai modifié mon code comme suit et cela semble fonctionner et avoir plus de sens maintenant :

Vieux

public MyBaseClass GetPopulatedBaseClass()
{
   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;
}

Nouveau

public void FillBaseClass(MyBaseClass myBaseClass)
{
   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...
}

Vieux

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

Nouveau

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = new MyDerivedClass();

   FillBaseClass(newDerivedClass);

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

8voto

Matthias Meid Points 8473

Vous pouvez effectuer la conversion vous-même, mais je ne vous le recommande pas. Jetez un coup d'œil à la Motif décorateur si vous voulez faire cela afin d'étendre la fonctionnalité d'un objet existant.

-1voto

Jan P. Points 2093

Non, ce n'est pas possible. La seule façon qui soit possible est

static void Main(string[] args)
{
    BaseClass myBaseObject = new DerivedClass();
    DerivedClass myDerivedObject = myBaseObject as DerivedClass;

    myDerivedObject.MyDerivedProperty = true;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X