Il y a beaucoup de code dans l'un de nos projets qui ressemble à ceci:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (s == null)
{
return "Foo";
}
return $({s}Foo);
}
}
Y a-t-il une raison explicite de le faire autre que "il est plus facile de rendre le type public plus tard?"
Je soupçonne que cela n'a d'importance que dans des cas très étranges (réflexion dans Silverlight) ou pas du tout.
return s + "Foo";
? L'+
opérateur ne se soucie pas des chaînes nulles ou vides.Réponses:
MISE À JOUR: Cette question a fait l'objet de mon blog en septembre 2014 . Merci pour la grande question!
Il y a un débat considérable sur cette question, même au sein de l'équipe de compilation elle-même.
Tout d'abord, il est sage de comprendre les règles. Un membre public d'une classe ou d'une structure est un membre accessible à tout ce qui peut accéder au type conteneur . Ainsi, un membre public d'une classe interne est effectivement interne.
Alors maintenant, étant donné une classe interne, ses membres auxquels vous souhaitez accéder dans l'assembly doivent-ils être marqués comme publics ou internes?
Mon opinion est la suivante: marquer ces membres comme publics.
J'utilise "public" pour signifier "ce membre n'est pas un détail d'implémentation". Un membre protégé est un détail d'implémentation; il y aura quelque chose qui sera nécessaire pour faire fonctionner une classe dérivée. Un membre interne est un détail d'implémentation; quelque chose d'autre interne à cet assembly a besoin du membre pour fonctionner correctement. Un membre public dit que "ce membre représente la fonctionnalité clé et documentée fournie par cet objet".
Fondamentalement, mon attitude est la suivante: supposons que j'ai décidé de faire de cette classe interne une classe publique. Pour ce faire, je veux changer exactement une chose : l'accessibilité de la classe. Si transformer une classe interne en classe publique signifie que je dois également transformer un membre interne en membre public, alors ce membre faisait partie de la surface publique de la classe, et il aurait dû être public en premier lieu.
D'autres personnes sont en désaccord. Il y a un contingent qui dit qu'ils veulent pouvoir regarder la déclaration d'un membre et savoir immédiatement si elle va être appelée uniquement à partir du code interne.
Malheureusement, cela ne fonctionne pas toujours bien; par exemple, une classe interne qui implémente une interface interne doit toujours avoir les membres d'implémentation marqués comme publics, car ils font partie de la surface publique de la classe .
la source
public
est très convaincant. Cependant, je trouve que "ça ne marche pas toujours bien ..." est particulièrement puissant. La perte de cohérence dévalue tous les avantages «en un coup d'œil». Utiliserinternal
de cette manière signifie construire délibérément des intuitions qui sont parfois fausses. Avoir une intuition presque correcte est l'OMI une chose horrible à avoir pour la programmation.Si la classe l'est
internal
, peu importe du point de vue de l'accessibilité que vous marquiez une méthodeinternal
oupublic
. Cependant, il est toujours bon d'utiliser le type que vous utiliseriez si la classe l'étaitpublic
.Alors que certains ont dit que cela facilite les transitions de
internal
àpublic
. Il fait également partie de la description de la méthode.Internal
les méthodes sont généralement considérées comme dangereuses pour un accès sans entrave, tandis que lespublic
méthodes sont considérées comme (principalement) des jeux gratuits.En utilisant
internal
oupublic
comme vous le feriez dans unepublic
classe, vous vous assurez que vous communiquez le style d'accès attendu, tout en facilitant le travail requis pour créer la classepublic
à l'avenir.la source
Je marque souvent mes méthodes dans des classes internes publiques au lieu de internes car a) cela n'a pas vraiment d'importance et b) j'utilise interne pour indiquer que la méthode est délibérément interne (il y a une raison pour laquelle je ne veux pas exposer cela Par conséquent, si j'ai une méthode interne, je dois vraiment comprendre la raison pour laquelle elle est interne avant de la changer en public alors que si je traite avec une méthode publique dans une classe interne, je dois vraiment réfléchir à la raison pour laquelle la méthode la classe est interne par opposition à la raison pour laquelle chaque méthode est interne.
la source
Je soupçonne "qu'il est plus facile de rendre le type public plus tard?" est-ce.
Les règles de portée signifient que la méthode ne sera visible qu'en
internal
tant que - donc peu importe que les méthodes soient marquéespublic
ouinternal
.Une possibilité qui vient à l'esprit est que la classe était publique et a ensuite été remplacée par
internal
et que le développeur n'a pas pris la peine de changer tous les modificateurs d'accessibilité de la méthode.la source
Dans certains cas, il se peut également que le type interne implémente une interface publique, ce qui signifierait que toutes les méthodes définies sur cette interface devront toujours être déclarées publiques.
la source
C'est la même chose, la méthode publique sera vraiment marquée comme interne car elle est à l'intérieur d'une classe interne, mais elle a un avantage (comme vous l'avez invité), si vous voulez marquer la classe comme publique, vous devez changer moins de code.
la source
internal
indique que le membre n'est accessible que depuis le même assemblage. D' autres classes dans cette assemblée peuvent accéder auinternal public
membre, mais ne seraient pas en mesure d'un accèsprivate
ouprotected
membre,internal
ou non.la source
internal
au lieu depublic
, leur visibilité ne changerait pas. Je pense que c'est ce que le PO demande.J'ai en fait eu du mal avec ça aujourd'hui. Jusqu'à présent, j'aurais dit que les méthodes devraient toutes être marquées avec
internal
si la classe étaitinternal
et aurait considéré autre chose que du mauvais codage ou de la paresse, spécialement dans le développement d'entreprise; cependant, j'ai dû sous-classer unepublic
classe et remplacer l'une de ses méthodes:La méthode DOIT être
public
et cela m'a fait penser qu'il n'y a vraiment aucun intérêt logique à définir des méthodes comme àinternal
moins qu'elles ne le soient vraiment, comme l'a dit Eric Lippert.Jusqu'à présent, je ne me suis jamais vraiment arrêté pour y penser, je l'ai juste accepté, mais après avoir lu le post d'Eric, cela m'a vraiment fait réfléchir et après beaucoup de délibérations, cela a beaucoup de sens.
la source
Il y a une différence. Dans notre projet, nous avons créé de nombreuses classes internes, mais nous effectuons des tests unitaires dans un autre assembly et dans nos informations d'assembly, nous avons utilisé InternalsVisibleTo pour permettre à l'assembly UnitTest d'appeler les classes internes. J'ai remarqué que si la classe interne a un constructeur interne, nous ne pouvons pas créer d'instance à l'aide d'Activator.CreateInstance dans l'assembly de test unitaire pour une raison quelconque. Mais si nous changeons le constructeur en public mais que la classe est toujours interne, cela fonctionne très bien. Mais je suppose que c'est un cas très rare (comme Eric l'a dit dans le post original: Reflection).
la source
Je pense avoir une opinion supplémentaire à ce sujet. Au début, je me demandais comment il était logique de déclarer quelque chose au public dans une classe interne. Ensuite, je me suis retrouvé ici, lisant que cela pourrait être bien si vous décidez plus tard de changer la classe en public. Vrai. Donc, un motif s'est formé dans mon esprit: si cela ne change pas le comportement actuel, alors soyez permissif et autorisez des choses qui n'ont pas de sens (et qui ne blessent pas) dans l'état actuel du code, mais plus tard, si vous changer la déclaration de la classe.
Comme ça:
Selon le "modèle" que j'ai mentionné ci-dessus, cela devrait être parfaitement bien. Il suit la même idée. Il se comporte comme une
private
méthode, car vous ne pouvez pas hériter de la classe. Mais si vous supprimez lasealed
contrainte, elle est toujours valide: les classes héritées peuvent voir cette méthode, ce que je voulais absolument atteindre. Mais vous obtenez un avertissement:,CS0628
ouCA1047
. Les deux visent à ne pas déclarer deprotected
membres dans unesealed
classe. De plus, j'ai trouvé un accord total sur le fait que cela n'a pas de sens: avertissement «membre protégé dans une classe scellée» (une classe singleton)Donc, après cet avertissement et la discussion liée, j'ai décidé de tout rendre interne ou moins, dans une classe interne, car cela correspond plus à ce genre de pensée, et nous ne mélangeons pas différents "modèles".
la source