82 votes

Quel est le cas d'utilisation du modificateur "private protected" (C# 7.2) ?

C# 7.2 introduit le modificateur private protected .

J'ai toujours protégé l'accès aux champs par des propriétés, en autorisant l'accès par les méthodes Get/Set, car je ne veux généralement pas que l'état interne de mon objet soit modifié par autre chose que ma propre classe.

J'essaie de comprendre pourquoi l'équipe du langage C# a ajouté cette fonctionnalité. Après une recherche approfondie sur Google, ainsi que la lecture et le visionnage des médias " quoi de neuf " (j'ai regardé l'émission Communiqué de presse , détails et vidéo de Mads Torgerson ), je ne suis toujours pas le plus sage.

Pour moi, cela semble permettre à un développeur de briser le principe de substitution de Liskov, mais c'est peut-être parce que je ne comprends pas pourquoi cette fonctionnalité existe maintenant.

Je comprends comment il peut être utilisé, mais pas pourquoi - s'il vous plaît, quelqu'un peut-il fournir un exemple d'utilisation réelle plutôt que celui inventé dans les documents MSDN ?

4 votes

Êtes-vous sûr de comprendre ce que fait ce modificateur ?

0 votes

Probablement parce que le CLR le supporte, voir MethodAttributes.FamANDAssem . C# déjà supporté internal protected qui est MethodAttributes.FamORAssem il est logique d'être exhaustif

0 votes

De quelle manière pensez-vous que cela brise le PSL ?

90voto

Evk Points 17804

Avant C# 7.2, nous avions protected internal modificateur. Cela signifie en réalité protégé OU interne, c'est-à-dire - membre A est accessible aux classes filles et également à toute classe de l'assemblage courant, même si cette classe n'est pas fille de la classe A (de sorte que la restriction impliquée par "protégé" est relâchée).

private protected signifie en réalité protégé ET interne. En d'autres termes, le membre n'est accessible qu'aux classes enfant qui sont dans la même assemblée, mais pas aux classes enfant qui sont en dehors de l'assemblée (ainsi, la restriction impliquée par "protected" est réduite - elle devient encore plus restrictive). C'est utile si vous construisez une hiérarchie de classes dans votre assembly et que vous ne voulez pas que des classes enfants d'autres assemblies puissent accéder à certaines parties de cette hiérarchie.

Nous pouvons prendre l'exemple suivant Jon Skeet fourni par dans les commentaires . Supposons que vous ayez la classe

public class MyClass {

}

Et vous voulez pouvoir en hériter uniquement dans l'assemblage actuel, mais vous ne voulez pas autoriser l'instanciation directe de cette classe, sauf à partir de cette hiérarchie de classes.

L'héritage uniquement dans l'assemblage actuel peut être réalisé avec le constructeur interne

public class MyClass {
    internal MyClass() {
    }
}

Empêcher l'instanciation directe, sauf dans la hiérarchie de la classe actuelle, peut être réalisé avec un constructeur protégé :

public class MyClass {
    protected MyClass() {
    }
}

Et pour obtenir les deux, vous devez private protected constructeur :

public class MyClass {
    private protected MyClass() {
    }
}

1 votes

@TimSchmelter ils sont similaires dans le sens où ils impliquent tous deux des restrictions sur les classes enfants (protected) et sur l'assemblage actuel (internal). Elles combinent simplement ces restrictions d'une manière différente (et vs ou).

0 votes

Désolé, j'ai supprimé mon commentaire parce qu'il était basé sur une opinion. Mais je pense toujours que protected est "plus similaire" que protected internal (modificateur d'accès très déroutant car il s'agit d'une assemblée publique). Le site protected Le modificateur d'accès a le même contrat : seulement accessible dans le même type ou les types dérivés de celui-ci. Mais son champ d'application n'est pas limité à cet assemblage, contrairement aux modificateurs d'accès suivants private internal . Ainsi, si un membre est protected mais vous devez éviter qu'il soit accessible de l'extérieur de l'assemblée. Vous devez private protected .

1 votes

Donc, voilà ce que j'ai compris en lisant l'article. Page MSDN . Ce que je ne comprends pas, c'est que por qué vous ne voudrez jamais faire ce qu'ils décrivent - c'est-à-dire accéder à un champ d'une classe de base à partir de la classe dérivée (dans la même assemblée) sans introduire une propriété. Si l'exemple était laissé tel que le vôtre, alors c'est parfaitement logique (et j'ai aimé la façon dont vous décrivez la différence entre protected internal et private protected). Peut-être que j'ai juste un parti pris contre l'exemple MSDN !

41voto

Suren Srapyan Points 42277

Pour deux mots Les modificateurs d'accès J'ai ce concept - le premier accesseur est lié à un autre assemblage, le second à l'assemblage dans lequel il a été défini.

interne protégé

  • protégé dans un autre assemblage : accessible uniquement dans les classes filles.

  • interne dans l'assemblée actuelle : accessible par tous les membres de l'assemblée actuelle.

privé protégé

  • privé dans une autre assemblée : n'est pas accessible.
  • protégé dans l'assemblage courant : accessible uniquement dans les classes filles.

1 votes

Super, c'est très facile et très logique. Cela m'a aidé à comprendre tout ce qui est confus. Merci !

0 votes

Cela peut dérouter certaines personnes au début, ce qui a été le cas pour moi, parce que je ne pouvais pas comprendre pourquoi internal and protected a été défini comme suit private protected et ensuite internal protected voulait dire autre chose. Je trouve qu'il est facile de le comprendre de cette façon : private protected == interne ET protégé tandis que internal protected == interne OU protégé

9voto

Matthew Watson Points 30804

Supposons que vous ayez une classe interne appelée SomeHelper que vous souhaitez utiliser dans le cadre de l'implémentation d'une classe de base abstraite publique :

public abstract class Test
{
    // Won't compile because SomeHelper is internal.
    protected SomeHelper CreateHelper()
    {
        return new SomeHelper();
    }

    public int Func(int x)
    {
        var helper = CreateHelper();
        return helper.DoSomething(x);
    }
}

internal class SomeHelper
{
    public virtual int DoSomething(int x)
    {
        return -x;
    }
}

Cela ne compilera pas car vous ne pouvez pas avoir une méthode protégée retournant un type interne. Votre seul recours est de ne pas utiliser SomeHelper de cette manière, ou de faire SomeHelper public.

(Vous pourriez faire SomeHelper une classe interne protégée de Test mais ça ne marchera pas si SomeHelper est destiné à être utilisé par d'autres classes qui ne dérivent pas de la classe de base).

Avec l'introduction de la private protected vous pouvez déclarer CreateHelper() comme ça :

private protected SomeHelper CreateHelper()
{
    return new SomeHelper();
}

Maintenant, il compilera, et vous n'avez pas à exposer vos internes.

1 votes

Vous pouvez soigner votre SomeHelper como protected classe intérieure de Test alors il compilera (à propos de "Votre seul recours...").

0 votes

@Evk Ah oui, je vais ajouter cela (mais alors il ne s'agit pas d'utiliser SomeHelper "de cette manière", bien sûr, ce qui est ce que je voulais vraiment dire).

0 votes

Cela peut aussi être très utile

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X