Pourquoi C # ne prend pas en charge l’intersection de l’accessibilité protégée et de l’accessibilité interne?

interne protégé:

L’ union de l’ accessibilité protégée et interne (c’est moins ressortingctif que protégé ou interne seulement)

Le CLR a le concept d’ intersection d’accessibilité protégée et interne , mais C # ne le supporte pas.

Donc ma question est:

Quel est le sens de l’omission de ce modificateur d’access , existe-t-il une raison concrète? Alors pourquoi C # ne devrait pas le supporter?

Mise à jour: C # 7.2 introduit ceci avec le modificateur d’access private protected , qui semble faux à plusieurs égards, mais évite en grande partie le risque de confusion que je décris ci-dessous. C’est peut-être le meilleur d’un mauvais groupe.

Personnellement, je l’ai voulu plusieurs fois. Il arrive que l’on expose une classe et une ou plusieurs classes qui en dérivent comme public dans un assemblage et qu’il arrive qu’un membre de la classe de base ne soit utilisé que par ces classes dérivées et qu’il ne soit pas exposé à des classes protégées dans d’autres classes. assemblies (assez souvent le constructeur, afin d’empêcher d’autres classes d’avoir des classes qui en dérivent).

Il est bien sûr toujours utile de définir votre access le plus ressortingctif possible. L’intersection de protected et internal est donc exactement ce que nous voulons ici.

Au lieu de cela, j’ai dû le supprimer en déclarant le membre internal . Il existe maintenant un potentiel de bogues dans mon code qui n’aurait pas existé si j’avais utilisé un langage qui me permettait d’utiliser cette intersection.

Cependant, considérons les inconvénients.

Dans l’état actuel des choses, il existe une certaine confusion quant à la manière dont protected internal donne à l’union de protected et internal . C’est probablement l’access le plus mal compris, à en juger par les questions posées sur des sites comme celui-ci.

Comment devrions-nous l’appeler? internal protected ? Pouvez-vous imaginer à quelle fréquence les gens pourraient confondre cela avec la protected internal ? Nous voudrions quelque chose de plus différencié, et nous voudrions qu’il en soit de même pour les applications internal protected (car nous avons encore accru son risque de confusion). Ce n’est pas un problème impossible à résoudre, mais il est également judicieux de limiter le nombre de mots-clés.

Même si la réponse à la question de nommage est parfaite, le risque de confusion lié à l’introduction d’un autre niveau d’access n’est pas totalement écarté.

Alors, gardons cela à l’esprit, examinons à nouveau l’aspect positif. Nous n’avons plus besoin de modifier les temps dont nous avons besoin en utilisant internal , ce qui réduit le nombre de bugs causés par l’utilisation inappropriée d’un tel membre. D’accord, à quelle fréquence cela arrive-t-il et quelle est la probabilité que de tels insectes soient réellement? Pas très souvent vraiment et peu probable.

Dans l’ensemble, par conséquent, même si je souhaite parfois que C # ait cela, une pause d’un moment me rend normalement heureux que ce ne soit pas le cas.

L’intersection de protected et internal passerait à un simple internal pour code externe à votre bibliothèque, ce qui signifie qu’elle ne serait pas accessible, que ce soit à partir de classes dérivées ou autrement.

En tant que tel, le seul avantage d’une protected internal intersection servirait à vous discipliner, en tant que développeur de votre bibliothèque, à ne pas accéder au type / membre sauf aux mêmes classes ou aux classes dérivées de votre bibliothèque. Cela ne fera aucune différence pour les utilisateurs de votre bibliothèque, car sa sémantique serait identique à un simple internal .

Cela dit, je n’aurais pas trouvé déraisonnable qu’il soit autorisé en C #. L’autodiscipline est souvent utile; c’est la raison pour laquelle les concepteurs de langage ont différencié private et internal , bien que les deux soient identiques pour les consommateurs externes.

Cependant, comme la distinction entre l’intersection et la plaine internal est faible, ils ont probablement choisi de l’exclure afin d’atténuer le risque de confusion des développeurs avec l’union protected internal plus utile.

C’était une décision de conception, mais réfléchissez à ce que cela signifie:

  • accessible uniquement aux classes dérivées du même assemblage.

Ce n’est pas une limite très utile, je ne peux pas penser à un cas d’utilisation clair.
Et c’est pourquoi il n’a probablement pas valu la peine de proposer un nouveau mot-clé (-combinaison).

Je préférerais demander pourquoi le CLR le soutient. Orthogonalité je suppose.

Alors pourquoi C # ne devrait pas le supporter?

Mauvaise question. La question devrait être “pourquoi C # devrait-il supporter les protected and internal ?”

N’oubliez pas que l’état naturel d’une fonctionnalité est qu’il ne soit pas implémenté. L’implémentation d’une fonctionnalité coûte très cher en termes de ressources, de tests et, n’oublions pas, de coût d’opportunité (autrement dit, elle remplace d’autres fonctionnalités). Donc, pour surmonter cette dépense, la mise en œuvre d’une fonctionnalité permettant de surmonter ces coûts devrait présenter un avantage extrêmement clair.

En particulier, quelle est la valeur de protected and internal ? Il n’y a vraiment aucune raison de limiter l’accessibilité aux classes dérivées du même assemblage.

OMI c’est bizarre le CLR le supporte, mais c’est le cas. Cela ne veut pas dire que C # doit le faire.

Je voulais poser la même question, mais heureusement, SO a trouvé celle-ci pour moi.

Je peux comprendre le sharepoint vue selon lequel il faudrait au moins un nouveau mot clé ou une nouvelle sémantique pour les mots clés existants. Il n’a donc pas été pris en charge car le rapport coût / avantages ne lui était pas favorable.

Cependant, je me demande s’il est légitime d’éviter de mettre en œuvre cette fonctionnalité CLR à cause d’un cas d’utilisation étroit ou parce que cela pourrait dérouter les gens.

L’un des arguments avancés ci-dessus est qu’il ne servirait qu’à faire respecter l’autodiscipline.

Mais on pourrait en dire autant de tout modificateur de visibilité non public . L’idée, par ailleurs, que cela ne s’appliquerait qu’à “un seul développeur d’une seule bibliothèque” est elle aussi manifestement erronée. De nombreuses bibliothèques sont développées par des équipes de personnes, et il est tout à fait naturel qu’un développeur de cette équipe ajoute un membre qu’il voudrait restreindre aux types internes dérivés de sa base.

Ensuite, il y a ce scénario:

 internal class Foo { } public class PublicBase { protected Foo MyFoo { get; set; } } 

Dans le cas présent, je souhaite exposer un type interne sur une classe, mais uniquement pour l’exposer à des types dérivés. Comme le type est interne, cela signifie implicitement les types dérivés dans le même assemblage. Les types externes peuvent toujours légitimement hériter de ce type, mais ils n’auront pas besoin d’utiliser ce membre.

Dans cette situation, je suis coincé: je ne peux ni utiliser protected ni utiliser protected internal .

Au lieu de cela, je dois utiliser internal , qui transmet de manière incorrecte aux autres membres de mon équipe l’utilisation du code en dehors de la classe. Bien sûr, je peux coller un commentaire dessus (et même coller l’ EditorBrowsableAtsortingbute de Never , mais cela le cacherait aussi des héritiers internes), mais ce n’est pas la même chose.

Dans l’état actuel des choses, la seule façon d’y parvenir est de pirater l’assembly avec une réécriture IL après la construction – mais j’ai besoin de cette visibilité (ou de l’absence de visibilité) au moment de la compilation, pas après sa construction.

En fin de compte, les arguments sur “quel (s) mot (s) clé (s) utiliserait-il” ou ” comment cela serait-il implémenté ” ne me paraissent pas pertinents: je suis le programmeur, pas le concepteur du langage C #.

De même, je dois dire que des arguments tels que “Eh bien, la protected internal est suffisamment déroutant pour beaucoup” sont également hors de propos. Il y a tellement de développeurs avec lesquels je suis entré en contact, que ce soit en personne ou virtuellement, qui ne comprennent pas des choses du type ?: Ou des contraintes génériques – devinez quoi, ils ne les utilisent pas! Cela ne signifie pas que je ne devrais pas.

Donc, oui, je comprends les raisons de ne pas le mettre en œuvre – mais je ne suis pas d’accord avec elles – par conséquent, ma réponse à la raison pour laquelle C # ne le supporte pas, c’est que les concepteurs de C # se sont trompés.

Et oui je suis prêt pour la chaleur que pourrait apporter à ma porte 🙂

Vous pouvez toujours faire:

 public MyExternallySealedClass { internal MyExternallySealedClass() {...} ... } 

Tant que vous ne laissez aucun consommateur externe instancier l’object, que feriez-vous s’il essayait de le dériver? Réponse courte, la fonctionnalité que vous demandez n’apporte rien de nouveau et vous avez déjà des outils pour faire ce que vous demandez.

Autant que je sache, vous pouvez utiliser l’intersection de modificateurs d’access protégés et d’access internes, mais pas avec l’interprétation souhaitée (peut-être à cause de ce que Henk a dit):

  1. Protected: le type ou le membre n’est accessible que par code dans la même classe ou structure, ou dans une classe dérivée.

  2. Interne: le type ou le membre est accessible par n’importe quel code du même assemblage, mais pas d’un autre assemblage.

  3. Protected Internal: le type ou le membre peut être accédé par n’importe quel code du même assembly ou par n’importe quelle classe dérivée d’un autre assembly.