web-dev-qa-db-fra.com

Pourquoi utiliser une méthode publique dans une classe interne?

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 (!string.IsNullOrEmpty(s)) return s + "Foo";
        return "Foo";
    }
}

Y a-t-il une raison explicite de faire cela autre que "il est plus facile de rendre le type public plus tard?"

Je suppose que cela ne compte que dans des cas Edge très étranges (réflexion dans Silverlight) ou pas du tout.

225
Eric Burcham

MISE À JOUR: Cette question était l'objet de mon blog en septembre 2014 . Merci pour la bonne question!

Le débat sur cette question est considérable, même au sein de l'équipe de compilation.

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 contenant. Ainsi, un membre public d'une classe interne est effectivement interne.

Alors maintenant, étant donné la classe interne, les membres auxquels vous souhaitez accéder à l’Assemblée devraient-ils être marqués comme publics ou internes?

Mon opinion est: marquez ces membres comme public.

J'utilise "public" pour signifier "ce membre n'est pas un détail de mise en œuvre". Un membre protégé est un détail d'implémentation; il y a quelque chose à ce sujet qui va être 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 à cette assemblée a besoin du député pour fonctionner correctement. Un membre public dit "ce membre représente la fonctionnalité documentée clé fournie par cet objet".

En gros, mon attitude est la suivante: supposons que je décide de faire de cette classe interne une classe publique. Pour ce faire, je souhaite changer exactement une chose : l'accessibilité de la classe. Si transformer une classe interne en classe publique signifie que je devrais également transformer un membre interne en membre public, ce membre faisait partie de la surface publique de la classe et il devrait ont été publics en premier lieu.

D'autres personnes ne sont pas d'accord. Il y a un contingent qui dit qu'il veut pouvoir jeter un coup d'œil sur la déclaration d'un membre et savoir immédiatement si elle sera appelée uniquement à partir d'un code interne.

Malheureusement, ça ne marche 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.

374
Eric Lippert

Si la classe est internal, peu importe l’accessibilité, que vous marquiez une méthode internal ou public. Cependant, il est toujours bon d'utiliser le type que vous utiliseriez si la classe était public.

Bien que certains aient dit que cela facilite les transitions de internal à public. Il fait également partie de la description de la méthode. Les méthodes Internal sont généralement considérées comme dangereuses pour un accès sans entrave, tandis que les méthodes public sont considérées comme étant (pour la plupart) des jeux gratuits.

En utilisant internal ou public comme vous le feriez dans une classe public, vous vous assurez que vous communiquez quel style d'accès est attendu, tout en allégeant le travail requis pour classe public dans le futur.

14
Guvante

Je marque souvent mes méthodes dans les classes internes public au lieu de internal car a) cela n'a pas vraiment d'importance et b) j'utilise internal pour indiquer que la méthode est volontairement interne (il y a une raison pour laquelle je ne souhaite pas exposer cette Par conséquent, si j’ai une méthode interne, je dois vraiment comprendre la raison pour laquelle elle est interne avant de la passer à public alors que si j’ai affaire à une méthode publique dans une classe interne, je dois vraiment réfléchir à la la classe est interne par opposition à pourquoi chaque méthode est interne.

10
Ɖiamond ǤeezeƦ

Je soupçonne qu '"il est plus facile de rendre le type public plus tard?" est-ce.

Les règles de cadrage signifient que la méthode ne sera visible que sous la forme internal. Le fait que les méthodes soient marquées public ou internal n'a donc aucune importance.

Une possibilité qui me vienne à l’esprit est que la classe was public a été changée en internal et que le développeur n’a pas pris la peine de changer tous les modificateurs d’accessibilité des méthodes.

8
Oded

Dans certains cas, il se peut également que le type interne implémente une interface publique, ce qui signifie que toutes les méthodes définies sur cette interface doivent toujours être déclarées comme publiques.

7
Trevor Pilley

C'est la même chose, la méthode publique sera vraiment marquée comme interne puisqu'elle fait partie d'une classe interne, mais elle a un avantage (en tant que invité), si vous voulez marquer la classe comme publique, vous devez modifier moins de code.

2
Mario Corchero

internal indique que le membre n'est accessible que depuis le même assemblage. Les autres classes de cette assemblée peuvent accéder au internal public membre, mais ne pourrait pas accéder à un membre private ou protected, internal ou non.

0
Ryan P

En fait, j'ai eu du mal avec cela aujourd'hui. Jusqu'à présent, j'aurais dit que toutes les méthodes devraient être marquées avec internal si la classe était internal et qu'elles auraient pris en compte autre chose que de mauvais codage ou de la paresse, spécialement dans le développement d'entreprise; cependant, j'ai dû sous-classer une classe public et redéfinir l'une de ses méthodes:

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

La méthode DOIT être public et cela m’a amené à penser qu’il n’y avait aucun point 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 n'ai jamais vraiment arrêté d'y penser, je l'ai simplement accepté, mais après avoir lu le message d'Eric, cela m'a vraiment fait réfléchir et, après de nombreuses délibérations, cela a beaucoup de sens.

0
Storm

Je pense avoir un avis 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. Puis je me suis retrouvé ici, en lisant que cela pourrait être bien si vous décidiez plus tard de changer de classe en public. Vrai. Donc, un motif s'est formé dans mon esprit: S'il ne modifie pas le comportement actuel, alors permissif, et permet des choses qui ne le sont pas est logique (et ne fait pas mal) dans l'état actuel du code, mais plus tard, si vous modifiez la déclaration de la classe.

Comme ça:

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

Selon le "motif" que j'ai mentionné ci-dessus, cela devrait parfaitement convenir. Cela suit la même idée. Elle se comporte comme une méthode private, car vous ne pouvez pas hériter de la classe. Mais si vous supprimez la contrainte sealed, elle est toujours valide: les classes héritées peuvent voir cette méthode, ce qui est absolument ce que je voulais réaliser. Mais vous recevez un avertissement: CS0628, ou CA1047. Les deux sont sur le point de ne pas déclarer protected membres dans une classe sealed. De plus, j’ai trouvé un accord total sur le fait que c’est insensé: avertissement 'Membre protégé dans une classe scellée' (une classe singleton)

Ainsi, après cet avertissement et la discussion liée, j'ai décidé de tout rendre interne ou moins, dans une classe interne, car elle est davantage conforme à ce type de pensée et nous ne mélangeons pas différents "modèles".

0
Hix

Il y a une différence. Dans notre projet, nous avons créé de nombreuses classes internes, mais nous effectuons des tests unitaires dans une autre assemblée et dans nos informations d'assemblage, nous avons utilisé InternalsVisibleTo pour permettre à l'assembly UnitTest d'appeler les classes internes. J'ai remarqué que si la classe internal a un constructeur interne, nous ne sommes pas en mesure de créer une 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 bien. Mais je suppose que c’est un cas très rare (comme Eric l’a dit dans le message original: Reflection).

0
Farrah Jiang