J'ai une classe de base abstraite et je souhaite déclarer un champ ou une propriété qui aura une valeur différente dans chaque classe qui hérite de cette classe parente.
Je veux le définir dans la classe de base afin de pouvoir le référencer dans une méthode de classe de base - par exemple en remplaçant ToString pour dire "Cet objet est de type propriété / champ ". J'ai trois façons dont je peux voir de faire cela, mais je me demandais - quelle est la meilleure façon acceptée de faire cela? Question de débutant, désolé.
Option 1:
utilisez une propriété abstraite et remplacez-la sur les classes héritées. Cela bénéficie d'être appliqué (vous devez le remplacer) et c'est propre. Mais, il semble légèrement faux de renvoyer une valeur de code en dur plutôt que d'encapsuler un champ et il s'agit de quelques lignes de code au lieu de juste. Je dois aussi déclarer un corps pour "set" mais c'est moins important (et il y a probablement un moyen d'éviter ce que je ne connais pas).
abstract class Father
{
abstract public int MyInt { get; set;}
}
class Son : Father
{
public override int MyInt
{
get { return 1; }
set { }
}
}
Option 2
Je peux déclarer un champ public (ou un champ protégé) et le remplacer explicitement dans la classe héritée. L'exemple ci-dessous me donnera un avertissement pour utiliser "nouveau" et je peux probablement le faire, mais cela ne semble pas bien et cela brise le polymorphisme, ce qui était le point essentiel. Cela ne semble pas être une bonne idée ...
abstract class Mother
{
public int MyInt = 0;
}
class Daughter : Mother
{
public int MyInt = 1;
}
Option 3
Je peux utiliser un champ protégé et définir la valeur dans le constructeur. Cela semble assez ordonné mais dépend de moi pour que le constructeur définisse toujours cela et avec plusieurs constructeurs surchargés, il y a toujours une chance qu'un chemin de code ne définisse pas la valeur.
abstract class Aunt
{
protected int MyInt;
}
class Niece : Aunt
{
public Niece()
{
MyInt = 1;
}
}
C'est un peu une question théorique et je suppose que la réponse doit être l'option 1 car c'est la seule option sûre , mais je me suis juste familiarisé avec C # et je voulais poser cette question à des personnes ayant plus d'expérience.
la source
Réponses:
Parmi les trois solutions, seule l' option 1 est polymorphe .
Les champs par eux-mêmes ne peuvent pas être remplacés. C'est exactement pourquoi l' option 2 renvoie l' avertissement de nouveau mot-clé.
La solution à l’avertissement n’est pas d’ajouter le mot-clé «nouveau», mais de mettre en œuvre l’option 1.
Si vous avez besoin que votre champ soit polymorphe, vous devez l'envelopper dans une propriété.
L'option 3 est OK si vous n'avez pas besoin d'un comportement polymorphe. Vous devez cependant vous rappeler que lors de l'accès à la propriété MyInt, la classe dérivée n'a aucun contrôle sur la valeur renvoyée. La classe de base seule est capable de renvoyer cette valeur.
Voici à quoi pourrait ressembler une implémentation véritablement polymorphe de votre propriété, permettant aux classes dérivées d'être en contrôle .
la source
L'option 2 est non-starter - vous ne pouvez pas remplacer les champs, vous ne pouvez que les masquer .
Personnellement, je choisirais l'option 1 à chaque fois. J'essaie de garder les champs privés à tout moment. C'est si vous avez vraiment besoin de pouvoir remplacer la propriété, bien sûr. Une autre option consiste à avoir une propriété en lecture seule dans la classe de base qui est définie à partir d'un paramètre de constructeur:
C'est probablement l'approche la plus appropriée si la valeur ne change pas pendant la durée de vie de l'instance.
la source
l'option 2 est une mauvaise idée. Il en résultera quelque chose appelé l'ombre; Fondamentalement, vous avez deux membres "MyInt" différents, l'un chez la mère et l'autre chez la fille. Le problème avec ceci, c'est que les méthodes qui sont implémentées dans la mère référenceront le "MyInt" de la mère tandis que les méthodes implémentées dans la fille feront référence au "MyInt" de la fille. cela peut causer de sérieux problèmes de lisibilité et de la confusion plus tard.
Personnellement, je pense que la meilleure option est 3; car il fournit une valeur centralisée claire et peut être référencé en interne par les enfants sans avoir à définir leurs propres champs - ce qui est le problème avec l'option 1.
la source
Tu pourrais faire ça
virtual vous permet d'obtenir une propriété un corps qui fait quelque chose tout en laissant les sous-classes le remplacer.
la source
Vous pouvez définir quelque chose comme ceci:
En définissant la valeur en lecture seule, cela garantit que la valeur de cette classe reste inchangée pendant toute la durée de vie de l'objet.
Je suppose que la question suivante est: pourquoi en avez-vous besoin?
la source
Si vous créez une classe et que vous souhaitez qu'il y ait une valeur de base pour la propriété, utilisez le
virtual
mot - clé dans la classe de base. Cela vous permet de remplacer éventuellement la propriété.En utilisant votre exemple ci-dessus:
Dans un programme:
la source
J'irais avec l'option 3, mais j'ai une méthode abstraite setMyInt que les sous-classes sont obligées de mettre en œuvre. De cette façon, vous n'aurez pas le problème d'une classe dérivée oubliant de la définir dans le constructeur.
Au fait, avec l'option un, si vous ne spécifiez pas set; dans votre propriété de classe de base abstraite, la classe dérivée n'aura pas à l'implémenter.
la source
Vous pouvez opter pour l'option 3 si vous modifiez votre classe de base abstraite pour exiger la valeur de propriété dans le constructeur, vous ne manquerez aucun chemin. J'envisagerais vraiment cette option.
Bien sûr, vous avez alors toujours la possibilité de rendre le champ privé puis, en fonction des besoins, d'exposer un getter de propriété protégée ou publique.
la source
J'ai fait ça...
De cette façon, vous pouvez toujours utiliser des champs.
la source
L'exemple d'implémentation lorsque vous souhaitez avoir une classe abstraite avec implémentation. Les sous-classes doivent:
Dans ce cas, les propriétés nécessaires à l'implémentation ne doivent pas être disponibles pour une utilisation sauf pour la classe abstraite et sa propre sous-classe.
la source