// Cannot change source code
class Base
{
public virtual void Say()
{
Console.WriteLine("Called from Base.");
}
}
// Cannot change source code
class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");
base.Say();
}
}
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
class Program
{
static void Main(string[] args)
{
SpecialDerived sd = new SpecialDerived();
sd.Say();
}
}
Le résultat est:
Appelé de Special Derived.
Appelé de dérivé. / * ce n'est pas prévu * /
Appelé depuis la base.
Comment puis-je réécrire la classe SpecialDerived afin que la méthode de la classe moyenne "Derived" ne soit pas appelée?
MISE À JOUR:
La raison pour laquelle je veux hériter de Derived au lieu de Base est la classe Derived contient beaucoup d'autres implémentations. Puisque je ne peux pas faire base.base.method()
ici, je suppose que la meilleure façon est de faire ce qui suit?
// Impossible de changer le code source
class Derived : Base
{
public override void Say()
{
CustomSay();
base.Say();
}
protected virtual void CustomSay()
{
Console.WriteLine("Called from Derived.");
}
}
class SpecialDerived : Derived
{
/*
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
*/
protected override void CustomSay()
{
Console.WriteLine("Called from Special Derived.");
}
}
c#
polymorphism
AZ.
la source
la source
Réponses:
Je veux juste ajouter ceci ici, car les gens reviennent encore à cette question même après plusieurs fois. Bien sûr, c'est une mauvaise pratique, mais il est toujours possible (en principe) de faire ce que l'auteur veut avec:
la source
Func<stuff>
lieu deAction
Ceci est une mauvaise pratique de programmation et n'est pas autorisé en C #. C'est une mauvaise pratique de programmation car
Les détails de la base sont les détails de mise en œuvre de la base; vous ne devriez pas compter sur eux. La classe de base fournit une abstraction par-dessus la grande base; vous devriez utiliser cette abstraction, pas construire un contournement pour l'éviter.
Pour illustrer un exemple spécifique du point précédent: s'il est autorisé, ce modèle serait encore une autre façon de rendre le code sensible aux échecs de classe de base fragile. Supposons que
C
dérive deB
qui dérive deA
. Le codeC
utilisebase.base
pour appeler une méthode deA
. Ensuite, l'auteur de seB
rend compte qu'il a mis trop de matériel en classeB
, et une meilleure approche consiste à créer une classe intermédiaireB2
qui dérive deA
etB
dérive deB2
. Après ce changement, le code inC
appelle une méthode inB2
, pas inA
, carC
l'auteur de a fait l'hypothèse que les détails d'implémentation deB
, à savoir que sa classe de base directe estA
, ne changerait jamais. De nombreuses décisions de conception en C # sont d'atténuer la probabilité de divers types de défaillances de base fragile; la décision de rendrebase.base
illégal empêche entièrement cette saveur particulière de ce modèle d'échec.Vous êtes dérivé de votre base parce que vous aimez ce qu'elle fait et que vous souhaitez la réutiliser et l'étendre. Si vous n'aimez pas ce qu'il fait et que vous voulez le contourner plutôt que de travailler avec, alors pourquoi en avez-vous dérivé en premier lieu? Dérivez vous-même de la grande base si c'est la fonctionnalité que vous souhaitez utiliser et étendre.
La base peut nécessiter certains invariants pour des raisons de sécurité ou de cohérence sémantique qui sont maintenus par les détails de la façon dont la base utilise les méthodes de la base grand. Permettre à une classe dérivée de la base d'ignorer le code qui maintient ces invariants pourrait mettre la base dans un état incohérent et corrompu.
la source
Vous ne pouvez pas à partir de C #. Depuis IL, cela est en fait pris en charge. Vous pouvez faire un appel non-virt à l'une de vos classes parentales ... mais ne le faites pas. :)
la source
La réponse (dont je sais que ce n'est pas ce que vous cherchez) est:
La vérité est que vous n'avez qu'une interaction directe avec la classe dont vous héritez. Considérez cette classe comme une couche - fournissant autant ou aussi peu de fonctionnalités de celle-ci ou de son parent qu'il le souhaite à ses classes dérivées.
ÉDITER:
Votre modification fonctionne, mais je pense que j'utiliserais quelque chose comme ceci:
Bien sûr, dans une implémentation réelle, vous pouvez faire quelque chose de plus comme ceci pour l'extensibilité et la maintenabilité:
Ensuite, les classes dérivées peuvent contrôler l'état de leurs parents de manière appropriée.
la source
Derived
laquelle des appelsBase.Say
, afin de pouvoir l'appelerSpecialDerived
? Plus simple, non?Pourquoi ne pas simplement convertir la classe enfant en une classe parente spécifique et appeler alors l'implémentation spécifique? Il s'agit d'une situation de cas particulier et une solution de cas particulier doit être utilisée. Vous devrez cependant utiliser le
new
mot - clé dans les méthodes enfants.la source
la source
Vous pouvez également créer une fonction simple dans la classe dérivée de premier niveau, pour appeler la fonction de base principale
la source
Mon 2c pour cela est d'implémenter la fonctionnalité dont vous avez besoin pour être appelé dans une classe de boîte à outils et de l'appeler de partout où vous en avez besoin:
Cela nécessite une réflexion sur les privilèges d'accès, vous devrez peut-être ajouter des
internal
méthodes d' accès pour faciliter la fonctionnalité.la source
Dans les cas où vous n'avez pas accès à la source de la classe dérivée, mais que vous avez besoin de toute la source de la classe dérivée en plus de la méthode actuelle, je vous recommande également de créer une classe dérivée et d'appeler l'implémentation de la classe dérivée.
Voici un exemple:
la source
Comme on peut le voir dans les articles précédents, on peut affirmer que si la fonctionnalité de classe doit être contournée, alors quelque chose ne va pas dans l'architecture de classe. Cela peut être vrai, mais on ne peut pas toujours restructurer ou refactoriser la structure de classe sur un grand projet mature. Les différents niveaux de gestion du changement peuvent être un problème, mais maintenir le même fonctionnement des fonctionnalités existantes après la refactorisation n'est pas toujours une tâche triviale, surtout si des contraintes de temps s'appliquent. Sur un projet mature, il peut être assez difficile d'empêcher divers tests de régression de réussir après une restructuration de code; il y a souvent des «bizarreries» obscures qui apparaissent. Nous avons eu un problème similaire dans certains cas, les fonctionnalités héritées ne devraient pas s'exécuter (ou devraient effectuer autre chose). L'approche que nous avons suivie ci-dessous, était de mettre le code de base à exclure dans une fonction virtuelle distincte. Cette fonction peut ensuite être remplacée dans la classe dérivée et la fonctionnalité exclue ou modifiée. Dans cet exemple, "Texte 2" peut être empêché de sortir dans la classe dérivée.
la source
Il semble y avoir beaucoup de ces questions concernant l'héritage d'une méthode membre d'une classe Grand-parent, la substituant dans une seconde classe, puis l'appel à sa méthode à partir d'une classe Petit-enfant. Pourquoi ne pas simplement hériter des membres des grands-parents jusqu'aux petits-enfants?
Cela semble simple ... le petit-enfant hérite de la méthode des grands-parents ici. Pensez-y ... c'est ainsi que "Object" et ses membres comme ToString () sont hérités de toutes les classes en C #. Je pense que Microsoft n'a pas fait un bon travail pour expliquer l'héritage de base. L'accent est trop mis sur le polymorphisme et la mise en œuvre. Quand je fouille dans leur documentation, il n'y a pas d'exemples de cette idée très basique. :(
la source
Si vous souhaitez accéder aux données de classe de base, vous devez utiliser le mot-clé "this" ou vous utilisez ce mot-clé comme référence pour la classe.
la source