web-dev-qa-db-fra.com

Pourquoi ne pouvons-nous pas changer le modificateur d'accès en surchargeant les méthodes en C #?

En C #, nous ne pouvons pas modifier le modificateur d'accès en redéfinissant une méthode de la classe de base .

Class Base
{
   **protected** string foo()
   {
       return "Base";
   }
}

Class Derived : Base
{
   **public** override string 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 restriction d'accès ???

38
Rumit Parakhiya

Changer le modificateur d'accès d'une méthode dans un type dérivé est inutile, c'est pourquoi ce n'est pas autorisé:

Cas 1: dérogation avec un accès plus restrictif

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<Base> list;
list.Add(new Derived());
list[0].A() //Runtime access exception

Cas 2: substitution avec un modificateur d'accès moins restrictif

Dans quel but? Cachez la méthode et vous avez terminé . Évidemment, si quelqu'un appelle via le type de base, il n'aura pas accès à la nouvelle méthode définie dans le type dérivé, mais cela correspond à la manière dont l'auteur du type de base a voulu que les choses soient ainsi. 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, la méthode new fonctionne alors parfaitement.

EDIT: Coque expansible 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 string WhoAmI()
    {
        return "Base";
    }
}

public class Derived : Base
{
    public new virtual string WhoAmI()
    {
        return "Derived";
    }
}

public class AnotherDerived : Derived
{
    public override string WhoAmI()
    {
        return "AnotherDerived";
    }
}

Avec le mot clé new, 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 méthode newvirtual, ainsi toute classe dérivant de Derived sera autorisée à la remplacer.

Ce qui n'est pas permis, c'est de demander à quelqu'un de faire 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 ignorer WhoAmI() ou non. Quoi qu’il en soit, cette situation ne peut jamais se produire car Base ne déclare pas une publicWhoAmI().

Ainsi, dans un C # théorique où Derived.WhoAmI() peut remplacer Base.WhoAmI(), cela ne présente aucun avantage pratique, car vous ne pourrez jamais appeler la méthode virtuelle à partir de la classe de base, de sorte que l'option new répond déjà à vos exigences.

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

27
InBetween

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’objet-état. 

9
Henk Holterman

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

Vous pouvez rendre l'accès 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.

1
Kon

si elle avait différents modificateurs d'accès, 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'accès?

0
peteisace

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’accès en redéfinissant les méthodes en C #.

0
Nikhil

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

Dans cet exemple particulier, si les entités externes commencent à modifier la propriété de l'objet 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?.

0