La création d'une instance de la classe dérivée par le biais de la classe de base sans le coder en dur
Mon problème est comme suit:
J'ai une classe de base qui doit être abstraite. Il possède plusieurs classes dérivées, chacun avec leurs propres propriétés qui sont contenus dans les Propriétés de membre.
J'ai besoin d'être en mesure de créer une nouvelle instance de l'une de ces classes dérivées, de sorte que tous les membres sont équivalentes, mais la modification de la nouvelle instance ne pas modifier l'original.
Enfin, je tiens à le faire sans avoir à coder en dur dans chaque type dérivé de la classe de base. (Ce qui serait, à vrai dire, la solution la plus simple, cependant, ce n'est pas le point)
Toutes les classes dérivées de satisfaire un "est-un" de la relation à la classe de base.
Voici le code:
public abstract class BaseClass
{
//Default properties here
int x, y, z, ...;
//Custom made class to hold custom properties
protected Attributes Properties;
public BaseClass createNewInstance()
{
return createNewInstanceStep1();
}
//Each derived class implements their own version of this,
//to handle copying any custom members contained in Properties.
protected abstract BaseClass createNewInstanceStep2();
protected BaseClass createNewInstanceStep1()
{
BaseClass newInstance = new BaseClass(); //<- Doesn't work because class is abstract
//Copy default properties
newInstance.x = x;
newInstance.y = y;
newInstance.z = z;
//Call the new instance's step 2 method, and return the result.
return newInstance.createNewInstanceStep2();
}
}
Le problème, c'est le code de BaseClass newKeyFrame = new BaseClass(); ligne. Comme la classe est abstraite, vous ne pouvez pas en créer une instance.
Le problème est que j'ai besoin d'être en mesure d'appeler le constructeur de ce type de la classe dérivée est, car ils ont tous un code différent dans leurs constructeurs qui ne peuvent pas être partagés.
J'ai entendu dire que l'utilisation de la Réflexion pourrait être une solution viable, cependant je n'ai aucune idée de comment.
Comment puis-je résoudre ce sans avoir à coder en dur dans un cas pour chaque type dérivé?
OriginalL'auteur Ipquarx | 2013-10-30
Vous devez vous connecter pour publier un commentaire.
Vous pourriez faire
createNewInstanceStep1
générique. J'ai aussi modifié leStep2
être de typevoid
(je m'attends à modifier la présente instance, de sorte que le retour serait toujoursreturn this;
de toute façon), parce que sinon, il n'est pas vraiment la façon dont je voudrais l'utiliser ici. Si ça n'a pas de sens de changer comme ça, puis tout mon approche de seulement de faire cette méthode générique ne fonctionne pas.Et
createNewInstance
utilise maintenant la réflexion pour appeler l'équivalent dereturn createNewInstanceStep1<this.GetType()>();
.Si cela ne fonctionne pas, une autre approche est un auto-référentielle de type générique. C'est bien pour éviter cela, bien que, parce que c'est source de confusion et dans l'ensemble pas une bonne conception.
where T : BaseClass, new()
est en train de faire?C'est deux contraintes:
T
doit être unBaseClass
(BaseClass
ou quelque chose qui s'étend), et celle-ci doit avoir un constructeur sans paramètre. Cela garantit que vous pouvez fairenew T()
et l'utilisationnewInstance
comme unBaseClass
.OriginalL'auteur Tim S.
Quel est le problème de laisser les classes dérivées ne l'instanciation de la nouvelle instance?
Non, vous ne le font pas. Comme vous pouvez le voir, la copie du ou des propriétés communes est gérée dans BaseClass.CopyData. Vous avez juste besoin d'être sûr de faire appel CopyData de chaque ChildClass.createNewInstance
Mal lu le code, oups. Oui, ce serait très bien fonctionner. Il EST plus simple et s'inscrit dans le même but. (albiet avec quelques modifications pour le code) +1
OriginalL'auteur Jon
Vous pouvez faire createNewInstanceStep1 un protected void init méthode qui lance cet objet, et de l'appeler dans chaque sous-classe du constructeur.
OriginalL'auteur Max Yankov
Comment allez-vous savoir quel type de l'instance à créer? Si vous avez une instance de la classe dérivée et que vous voulez créer une autre instance qui est essentiellement identique à elle, vous devriez avoir votre type de base de mettre en œuvre un virtuel protégé
CloneBase
méthode qui appelleMemberwiseClone
et toute la profondeur de la copie de la base type en sait, et un publicClone
méthode des chaînes deCloneBase
et les jette au type de base. Chacun des types dérivés doit l'emporter sur lesCloneBase
à la chaîne debase.CloneBase
et ajouter supplémentaire nécessaire profonde de la copie (cette étape peut être omise si aucune autre copie en profondeur la logique est nécessaire), et aussi de l'ombre au publicClone
méthode avec une que les chaînes deCloneBase
et convertit le résultat de son type [séparer lesCloneBase
rend possible à la fois de déclarer une nouvelleClone
méthode avec une signature différente, tout aussi primordial et le chaînage à la base de la méthode de classe].Si vous avez une instance existante de la nouvelle classe, mais veulent ses propriétés à être copié à partir de certains autres exemple, pourrait avoir un résumé
ConstructInstanceLike(x)
méthode qui chaque type dérivé serait mettre en œuvre pour appeler l'un de ses constructeurs, ou de se cloner lui-même et de modifier le clone de faire correspondre le passé-objet. Aucune approche est terriblement élégant, mais chacun peut travailler.Si vous ne disposez pas d'une instance existante de la nouvelle classe, vous aurez besoin d'un autre moyen d'obtenir quelque chose du type approprié. La plus belle approche est probablement pour stocker une collection de
Func<TParams, TResult>
délégués, une pour chaque type dérivé d'intérêt, puis d'appeler l'une de ces fonctions pour générer un objet de l'un des associés type dérivé. Il serait également possible de définir une interfacemais dans de nombreux cas, un délégué sera plus commode de travailler avec.
Un clone basé sur l'approche ne nécessite pas de codage en dur dans les différents classes dérivées qui ne pas ajouter de nouveaux membres exigent des travaux. Si vous utilisez la fonction approche fondée sur les lambdas, vous pourriez probablement créer une table assez bien avec une ligne de code source par type pris en charge (quelque chose comme
AddFactory<FooBar>((x) => new FooBar(x));
). Est-ce trop de "codage en dur" à votre goût?Evidemment c'est pas trop dur à faire, mais encore une fois, la question des états l'objectif est de ne pas coder en dur nécessaire que ce soit, et l'on a accepté la réponse c'est exactement pour moi. (Même si je dois admettre que cela fonctionne parfaitement bien)
La accepté de répondre exige que les classes dérivées public sans paramètre constructeurs. Si l'on était prêt à accepter cette condition, on n'aurait pas à utiliser la Réflexion pour créer les instances; et l'on pourrait créer une nouvelle instance et ensuite utiliser un
CopyFrom
méthode sur cette instance (qui elle pourrait hériter de la classe de base) pour copier ses membres. Une approche à l'aideMemberwiseClone
pourrait éviter la nécessité d'unenew
contrainte, si l'on devait faire attention à invalider toutes les données dans l'objet cloné, ce qui ne devrait pas être présent dans la nouvelle instance.OriginalL'auteur supercat