Menu

Modificateurs d'accès en C# : public, private, protected et internal

Les six modificateurs d'accès de C# (public, private, protected, internal, protected internal, private protected), ce que chacun autorise, les valeurs par défaut quand vous n'en écrivez aucun, et les erreurs de compilation qu'ils produisent.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Les modificateurs d'accès déterminent quel code peut utiliser un type ou un membre. C'est ainsi qu'une classe sépare la partie sur laquelle s'appuie le reste du code (sa surface publique) de la partie qu'elle est libre de modifier (ses détails internes). C# en a six, plus les valeurs par défaut que vous obtenez quand vous n'en écrivez aucun.

Les six modificateurs

ModificateurType qui le contientType dérivé, même assemblyAutre code, même assemblyType dérivé, autre assemblyAutre code, autre assembly
publicouiouiouiouioui
protected internalouiouiouiouinon
protectedouiouinonouinon
internalouiouiouinonnon
private protectedouiouinonnonnon
privateouinonnonnonnon

Un assembly est un projet compilé : le .dll ou le .exe qu'il produit. « Même assembly » signifie « même projet », c'est pourquoi internal fonctionne comme « visible pour mon code, caché pour les utilisateurs de ma bibliothèque ».

private et public : l'encapsulation

private est la valeur par défaut des membres et le bon choix pour la plupart des champs. La classe expose ce dont les appelants ont besoin via des méthodes et propriétés public, et ces méthodes gardent les données de l'objet cohérentes.

Sortie :

False
True
Priya: 180

Comme balance est privé, les seuls moyens de le modifier sont Deposit et TryWithdraw, et les deux appliquent les règles. Aucun autre code du programme ne peut créer un solde négatif, quelle que soit la façon dont il est écrit. C'est ce qu'apporte l'encapsulation : les règles vivent à un seul endroit.

private s'applique par type, pas par objet. Une méthode d'Account peut lire other.balance sur une autre instance d'Account, et c'est ainsi que s'écrivent en général Equals et les méthodes de comparaison.

protected : visible pour les classes dérivées

Un membre protected est caché au monde extérieur mais disponible pour les classes qui héritent de la classe qui le déclare.

Sortie :

Sam: 4000.00
Rita: 6400.00

Une règle surprend. Dans Manager, vous pouvez utiliser baseSalary sur this ou sur un autre Manager, mais pas sur un Employee quelconque :

class Manager : Employee
{
    public decimal Compare(Employee other)
    {
        return baseSalary - other.baseSalary;
        // error CS1540: Cannot access protected member 'Employee.baseSalary' via a qualifier
        // of type 'Employee'; the qualifier must be of type 'Manager' (or derived from it)
    }
}

La raison : other pourrait être un Contractor qui dérive aussi d'Employee, et protected donne accès à votre propre branche de la hiérarchie, pas à celle de vos frères.

Un champ protégé lie pour toujours chaque classe dérivée à ce champ. Beaucoup de bases de code préfèrent une propriété ou une méthode protected, ou gardent les champs privés et ne donnent aux classes dérivées que ce dont elles ont besoin.

internal : visible dans l'assembly

Les membres et types internal peuvent être utilisés par n'importe quel code du même projet et par rien à l'extérieur. Une bibliothèque s'en sert pour les fonctions auxiliaires sur lesquelles reposent ses classes publiques :

// In the MyShop.Pricing library project
public class PriceCalculator
{
    public decimal Total(Cart cart) => TaxRules.Apply(cart.Subtotal);
}

internal static class TaxRules   // callers of the library cannot see this class
{
    internal static decimal Apply(decimal amount) => amount * 1.2m;
}

Les types de premier niveau sont internal quand vous n'écrivez aucun modificateur. C'est pourquoi une classe que vous avez oublié de marquer public dans une bibliothèque de classes « manque » dans le projet qui la référence.

Les projets de tests unitaires sont des assemblies séparés, ils ne peuvent donc pas voir le code internal non plus. La correction standard est un attribut dans la bibliothèque :

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyShop.Pricing.Tests")]

protected internal et private protected

Ces deux modificateurs combinent les précédents, de façons opposées, et leurs noms se confondent facilement :

  • protected internal signifie protected ou internal : tout code du même assembly, plus les classes dérivées d'autres assemblies. C'est le plus large des deux.
  • private protected (C# 7.2) signifie protected et internal : seulement les classes dérivées qui sont aussi dans le même assembly. C'est le plus restreint, pour une classe de base dont les points d'extension doivent rester dans votre bibliothèque.
public class ReportBase
{
    protected internal string Title;      // same assembly, or subclasses anywhere
    private protected int RowLimit = 500; // subclasses in this assembly only (C# 7.2)
}

Valeurs par défaut quand vous n'écrivez rien

OùPar défautAutorisés
Type déclaré dans un namespaceinternalpublic, internal, file (C# 11)
Membre d'une classeprivateles six
Membre d'une structprivatepublic, internal, private (on ne peut pas hériter d'une struct)
Type imbriquéprivateles six
Membre d'interfacepublicmodificateurs explicites autorisés depuis C# 8
Membre d'enumpublicaucun

Être explicite coûte un mot et évite une question au lecteur suivant, c'est pourquoi la plupart des guides de style demandent le modificateur même quand il correspond à la valeur par défaut.

Accès au niveau des accesseurs

Une propriété ou un indexeur peut donner à l'un de ses accesseurs un modificateur plus restrictif que celui de la propriété elle-même :

Sortie :

report.pdf: 100%

Le modificateur de l'accesseur doit être plus restrictif que celui de la propriété, et un seul des deux accesseurs peut en avoir un.

Accessibilité incohérente

Un membre public ne peut pas exposer un type moins visible que lui, car les appelants recevraient quelque chose qu'ils n'ont pas le droit de nommer :

internal class Discount { }

public class Checkout
{
    public Discount Current() => null;
    // error CS0050: Inconsistent accessibility: return type 'Discount' is less accessible than method 'Checkout.Current()'
}

La même règle donne CS0051 pour les types de paramètres et CS0053 pour les types de propriétés. Corrigez en rendant le type aussi visible que le membre, ou le membre aussi caché que le type.

Choisir un modificateur

Commencez par le modificateur le plus restrictif qui fonctionne et n'élargissez que lorsqu'un appelant en a besoin. Rendre quelque chose plus visible plus tard est facile et ne casse jamais personne ; rendre quelque chose moins visible casse chaque appelant qui l'utilisait. En pratique : les champs private, les membres qui constituent la raison d'être de la classe public, les fonctions auxiliaires private, et les types propres à la bibliothèque internal.

Questions fréquentes

Quels sont les modificateurs d'accès en C# ?

Il y en a six : public (tout code), private (seulement le type qui le contient), protected (le type qui le contient et les types qui en dérivent), internal (tout code du même assembly), protected internal (même assembly, ou types dérivés n'importe où) et private protected (types dérivés du même assembly, C# 7.2). C# 11 a ajouté file pour les types visibles dans un seul fichier source.

Quel est le modificateur d'accès par défaut en C# ?

Les membres d'une classe ou d'une struct (champs, méthodes, propriétés, types imbriqués) sont private par défaut. Les types de premier niveau (une classe déclarée directement dans un namespace) sont internal par défaut. Les membres d'interface et les membres d'enum sont publics.

Que signifie protected en C# ?

Un membre protected est visible dans sa propre classe et dans toute classe qui en dérive, mais pas pour le reste du code. Une classe dérivée ne peut l'utiliser qu'à travers son propre type : dans Manager, this.baseSalary fonctionne, mais atteindre baseSalary sur un autre objet Employee donne l'erreur CS1540.

Qu'est-ce qu'internal en C# ?

internal rend un type ou un membre visible pour tout le code du même assembly (le .dll ou .exe compilé d'un même projet) et invisible à l'extérieur. C'est ainsi qu'une bibliothèque garde ses classes auxiliaires hors de son API publique. [assembly: InternalsVisibleTo("MyLib.Tests")] permet à un projet de test de les voir aussi.

Comment corriger « is inaccessible due to its protection level » ?

C'est l'erreur CS0122 : le code utilise un membre qu'il n'a pas le droit de voir, le plus souvent un champ laissé au private par défaut. Si du code extérieur doit le lire, exposez une propriété ou une méthode publique ; ne rendez pas simplement le champ public. S'il s'agit d'un type d'un autre projet, il est probablement internal.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER