Pourquoi ne pouvons-nous pas changer le modificateur d’access en surchargeant les méthodes en C #?

En C #, nous ne pouvons pas modifier le modificateur d’access en redéfinissant une méthode de la classe de base. par exemple

Class Base { **protected** ssortingng foo() { return "Base"; } } Class Derived : Base { **public** override ssortingng foo() { return "Derived"; } } 

Ce n’est pas valide en C #, cela donnera une erreur de compilation.

Je veux savoir la raison, pourquoi ce n’est pas permis. Y at-il un problème technique ou peut-il conduire à quelque chose qui n’est pas cohérent en termes de ressortingction d’access ???

Changer le modificateur d’access d’une méthode dans un type dérivé est inutile, c’est pourquoi il n’est pas autorisé:

Cas 1: dérogation avec un access plus ressortingctif

Ce cas n’est évidemment pas autorisé en raison de la situation suivante:

 class Base { public virtual void A() {} } class Derived: Base { protected override void A() } 

Maintenant nous pourrions dire:

 List list; list.Add(new Derived()); list[0].A() //Runtime access exception 

Cas 2: substitution avec un modificateur d’access moins ressortingctif

Dans quel but? Cachez la méthode et vous avez terminé. Évidemment, si quelqu’un appelle par le biais du type de base, il n’aura pas access à la nouvelle méthode définie dans le type dérivé, mais cela correspond à la façon dont l’auteur du type de base a voulu que les choses soient, de sorte que vous n’avez pas le “droit” de changer cela. Si vous souhaitez connaître les spécificités de l’appel de la classe dérivée à partir de la classe dérivée, dans ce cas, la new méthode fonctionne parfaitement.

EDIT: Etui à expansion 2

Ce que j’essaie de dire dans le cas 2, c’est que vous avez déjà les moyens de modifier l’accessibilité de toute méthode (virtuelle ou non) si vous souhaitez modifier l’accessibilité.

Considérons le code suivant:

 public class Base { protected virtual ssortingng WhoAmI() { return "Base"; } } public class Derived : Base { public new virtual ssortingng WhoAmI() { return "Derived"; } } public class AnotherDerived : Derived { public override ssortingng WhoAmI() { return "AnotherDerived"; } } 

Avec le new mot-clé, vous avez effectivement créé une nouvelle méthode virtuelle pour votre classe Derived avec le même nom et la même signature. Notez qu’il est AUTORISE de déclarer une new méthode virtual . Ainsi, toute classe dérivée de Derived sera autorisée à la remplacer.

Ce qui n’est pas permis, c’est que quelqu’un fasse ce qui suit:

  Base newBaseObject = new Derived(); newBaseObject.WhoAmI() //WhoAmI is not accessible. 

Mais ce fait n’a rien à voir avec le fait de pouvoir remplacer WhoAmI() ou non. Quoi qu’il en soit, cette situation ne peut jamais se produire car Base ne déclare pas un public WhoAmI() .

Donc, dans un C # théorique où Derived.WhoAmI() peut remplacer Base.WhoAmI() il n’ya aucun avantage pratique à le faire car vous ne pourrez jamais appeler la méthode virtuelle de la classe de base, de sorte que la new option répond déjà à vos besoins. exigences.

J’espère que cela rend les choses plus claires.

D’accord, j’ai trouvé une petite note d’Eric Lippert dans la référence Annotated C #:

Une méthode virtuelle remplacée est toujours considérée comme une méthode de la classe qui l’a introduite. Les règles de résolution de surcharge préfèrent dans certains cas les membres de types plus dérivés … le fait de surcharger une méthode ne “bouge” pas lorsque cette méthode appartient à cette hiérarchie.

Il s’agit donc d’une règle intentionnelle visant à éviter le problème de la «classe de base fragile» et à fournir un meilleur contrôle des versions, c’est-à-dire moins de problèmes lors du changement d’une classe de base.

Mais notez que cela n’a rien à voir avec la sécurité, la sécurité de type ou l’état d’object.

Si vous modifiez les modificateurs de visibilité d’un modificateur plus ressortingctif à un modificateur moins ressortingctif, vous autorisez les clients de classe à accéder aux méthodes conçues pour un usage interne. En gros, vous avez fourni un moyen de modifier un état de classe qui peut ne pas être sûr.

Vous pouvez rendre l’access de la classe dérivée inférieur à celui de la base, mais pas supérieur. Sinon, cela irait à l’encontre de la définition de base et exposerait ses composants au-delà de ce qui était prévu.

Réduire la visibilité est impossible car si Base.Member était visible et Derived.Member n’était pas visible, le concept entier de « Derived is a Base » serait rompu. Toutefois, il est peutêtre impossible d’augmenter la visibilité, peutêtre parce que les développeurs de langage pensent que modifier la visibilité serait une erreur la plupart du temps. Toutefois, vous pouvez toujours utiliser le new mot-clé pour masquer les membres de la classe de base en introduisant un membre portant le même nom mais un comportement différent. Ce nouveau membre appartient à l’interface du type dérivé. Vous pouvez donc bien sûr toujours accéder à l’interface du type de base en effectuant une conversion vers ce type de base. Selon la manière dont vous écrivez votre sous-classe, votre new membre peut effectivement augmenter la visibilité de la propriété de la classe de base. Toutefois, n’oubliez pas que la propriété de la classe de base peut toujours être consultée directement propriété).

La question ici est de savoir comment override et new le même membre nommé (identifiant) dans une sous-classe. Ce n’est apparemment pas possible. À tout le moins, je peux affirmer par des expériences que public new override ssortingng foo(){return "";} n’est pas une syntaxe pour cela. Cependant, vous pouvez obtenir le même effet en utilisant deux sous-classes:

 using System; class Base { protected virtual ssortingng foo() { return "Base"; } public void ExhibitSubclassDependentBehavior() { Console.WriteLine("Hi, I am {0} and {1}.", GetType(), foo()); } } abstract class AbstractDerived : Base { protected virtual ssortingng AbstractFoo() { return base.foo(); } protected override ssortingng foo() { return AbstractFoo(); } } class Derived : AbstractDerived { protected override ssortingng AbstractFoo() { return "Deprived"; } public new ssortingng foo() { return AbstractFoo(); } } static class Program { public static void Main(ssortingng[] args) { var b = new Base(); var d = new Derived(); Base derivedAsBase = d; Console.Write(nameof(b) + " -> "); b.ExhibitSubclassDependentBehavior(); // "b -> Hi, I am Base and Base." Console.WriteLine(nameof(d) + " -> " + d.foo()); // "d -> Deprived" Console.Write(nameof(derivedAsBase) + " -> "); derivedAsBase.ExhibitSubclassDependentBehavior(); // "derivedAsBase -> Hi, I am Derived and Deprived." } } 

La sous-classe intermédiaire ( AbstractDerived ) utilise le override et introduit un nouveau membre, nommé différemment, permettant à la sous-classe et aux sous-sous-classes de continuer à override le membre de la classe de base comme bon leur semble. La sous-sous-classe ( Derived ) utilise new pour introduire la nouvelle API. Etant donné que vous ne pouvez utiliser qu’un new identifiant ou override un identifiant particulier une seule fois par niveau de sous-classement, vous avez besoin de deux niveaux de sous-classement pour pouvoir utiliser efficacement les deux sur le même identifiant.

Donc, d’une certaine manière, vous pouvez modifier la visibilité tout en surchargeant les méthodes – c’est très difficile et il n’ya pas de syntaxe pour le faire avec un seul niveau d’inheritance. Cependant, vous devrez peut-être utiliser une astuce comme celle-ci en fonction des interfaces que vous essayez d’implémenter et de l’apparence de votre classe de base. Cela peut être ou ne pas être ce que vous voulez réellement faire. Mais je me demande toujours pourquoi C # ne supporte pas simplement cela pour commencer. IOW, cette «réponse» est simplement une reformulation de la question du PO avec une solution de contournement ;-).

Les raisons sont évidentes. Sécurité et intégrité des objects.

Dans cet exemple particulier, que se passe-t-il si des entités externes commencent à modifier la propriété de l’object qui est protégé en fonction de la classe de base? Les choses vont mal tourner. Qu’en est-il du code client écrit contre la classe de base à laquelle toute classe dérivée doit se conformer?

si elle avait différents modificateurs d’access, vous ne pouvez plus la considérer comme la même méthode. en quelque sorte suggère un problème avec la conception du modèle.

Une meilleure question serait pourquoi voudriez-vous changer les modificateurs d’access?

Le remplacement est un terme qui vous permet de modifier ou d’augmenter le comportement des méthodes d’une classe de base. Le remplacement vous donne le contrôle pour écrire une nouvelle logique pour une méthode existante.

Changer la signature d’une méthode de base d’une méthode s’apparente à écrire une nouvelle méthode au lieu de remplacer celle qui existe. Cela contredit le but de remplacer une méthode. Alors peut-être la raison pour laquelle vous ne pouvez pas changer le modificateur d’access en redéfinissant les méthodes en C #.