2012-02-12 4 views
3

Existe-t-il un moyen de transformer une classe de base en sa classe dérivée?Transformer une classe en une classe dérivée

Voici un exemple simple de deux classes:

namespace BLL 
{ 
    public class Contact 
    { 
     public int ContactID { get; set; } 
     public string Name { get; set; } 

     public Contact(){} 
    } 
} 

namespace BLL 
{ 
    public class SpecialContact : Contact 
    { 
     public SpecialContact(){} 
    } 
} 

Idéalement, je pouvais faire quelque chose comme ceci:

Contact contact = new Contact(); 
SpecialContact specialContact = new SpecialContact(); 

contact.ContactID = 123; 
contact.Name = "Jeff"; 

specialContact = contact; 

Ce code bien sûr renvoie une erreur. En dehors de l'écriture d'un autre constructeur pour SpecialContact ou d'une méthode qui définit chaque propriété, existe-t-il une autre solution?

+2

Cela n'a aucun sens. Un contact spécial n'est pas un contact. Que signifierait * transformer * un contact en un contact spécial? –

+0

@kerrek - la logique du domaine peut appeler un changement de contrat dans un contrat spécial. Mais ce n'est pas (ne devrait pas) être possible avec quelque chose comme un typecast dans le code. –

+0

Merci à tous. C'est logique pourquoi vous ne pouvez pas effectuer cette action. – Josh

Répondre

3

Il est illégal d'affecter la référence de classe Base à la variable de référence de classe Derived. La variable de type X ne peut être qu'une référence à un objet de type X ou dérivée.

Vous avez probablement besoin d'une autre instance de SpecialContact qui contient les mêmes données que l'objet existant. Il n'y a aucun moyen d'éviter la copie manuelle.

J'utilise la méthode d'extension suivante quand j'ai besoin de copier les propriétés correspondant d'un objet à un autre incompatible (1):

public static void AssignFrom(this object destination, object source) { 
    Type dest_type = destination.GetType(); 
    Type source_type = source.GetType(); 

    var matching_props = from d in dest_type.GetProperties() 
         join s in source_type.GetProperties() 
         on d.Name equals s.Name 
         where d.IsWritable() && s.IsReadable() 
         select new { 
          source = s, 
          destination = d 
         }; 

    foreach (var prop in matching_props) { 
    prop.destination.SetValue(destination, prop.source.GetValue(source, null), null); 
    } 
} 

Ensuite, vous pouvez faire:

specialContact.assignFrom(contact); 

S'il vous plaît considérer C'est une solution de contournement. La solution appropriée serait de concevoir correctement votre hiérarchie de classe où vous ne venez pas à ce problème.


1 Remarque: il correspond aux propriétés par leur nom et suppose qu'elles sont du même type.

+0

Bonne solution, je cherche juste à éviter de copier les propriétés. – Josh

1

Ce code produit bien sûr une erreur. En dehors de l'écriture d'un autre constructeur pour SpecialContact ou d'une méthode qui définit chaque propriété, existe-t-il une autre solution?

Non, il n'y a pas d'autre moyen. La réflexion peut vous aider si vous voulez éviter de faire toute la copie manuelle.

2

En dehors de l'écriture d'un autre constructeur pour SpecialContact ou d'une méthode qui définit chaque propriété, existe-t-il une autre solution?

Non, pas vraiment.
Vous pouvez l'automatiser avec Reflection, mais c'est à peu près tout.

Mais notez qu'avec un design approprié, cela ne devrait presque jamais être nécessaire. Ce n'est pas une utilisation normale des classes (dérivées).

Si les contrats peuvent être modifiés dans SpecialContracts au fil du temps, vous pouvez soit créer un objet, soit le modéliser avec une propriété ContactType et éventuellement une composition.

3

Si vous êtes simplement intéressé à propriétés de copie d'une instance de classe à une autre (quelle que soit la relation de ces classes), vous pouvez utiliser un outil de cartographie comme AutoMapper.

Votre exemple spécifique ressemblerait à ceci:

Mapper.CreateMap<Contact, SpecialContact>(); 
Contact contact = new Contact(); 
contact.ContactID = 123; 
contact.Name = "Jeff"; 
SpecialContact specialContact = Mapper.Map<Contact, SpecialContact>(contact); 
+0

Correct, je suis juste intéressé par la copie des propriétés. AutoMapper semble une bonne solution. – Josh

1

Outre reconsidérant votre hiérarchie d'héritage qui vous oblige à faire cette opération un peu non orthodoxes, vous avez plusieurs solutions, toutes nécessitant un certain codage.

  • Vous pouvez ajouter un opérateur de conversion explicite à votre classe de base
  • Vous pouvez ajouter une méthode d'extension qui fait la copie pour vous

En ce qui concerne la transformation de votre hiérarchie d'héritage va, vous pouvez utiliser le Decorator Design Pattern pour ajouter des fonctionnalités spéciales à votre classe Contact, en lui donnant la fonctionnalité d'un SpecialContact sans sous-classe.

Questions connexes