Menu

C# Zugriffsmodifizierer: public, private, protected und internal

Die sechs Zugriffsmodifizierer in C# (public, private, protected, internal, protected internal, private protected), was jeder erlaubt, die Standardwerte, wenn du keinen angibst, und die Compilerfehler, die sie erzeugen.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Zugriffsmodifizierer entscheiden, welcher Code einen Typ oder Member verwenden darf. Mit ihnen trennt eine Klasse den Teil, auf den anderer Code sich verlässt (ihre öffentliche Oberfläche), von dem Teil, den sie frei ändern darf (ihre Interna). C# hat sechs davon, plus die Standardwerte, die du bekommst, wenn du keinen angibst.

Die sechs Modifizierer

ModifiziererEnthaltender TypAbgeleiteter Typ, gleiche AssemblyAnderer Code, gleiche AssemblyAbgeleiteter Typ, andere AssemblyAnderer Code, andere Assembly
publicjajajajaja
protected internaljajajajanein
protectedjajaneinjanein
internaljajajaneinnein
private protectedjajaneinneinnein
privatejaneinneinneinnein

Eine Assembly ist ein kompiliertes Projekt: die .dll oder .exe, die es erzeugt. „Gleiche Assembly“ bedeutet „gleiches Projekt“, deshalb funktioniert internal als „für meinen Code sichtbar, vor den Nutzern meiner Bibliothek verborgen“.

private und public: Kapselung

private ist der Standard für Member und für die meisten Felder die richtige Wahl. Die Klasse stellt über public-Methoden und -Properties bereit, was Aufrufer brauchen, und diese Methoden halten die Daten des Objekts konsistent.

Ausgabe:

False
True
Priya: 180

Weil balance privat ist, lässt es sich nur über Deposit und TryWithdraw ändern, und beide setzen die Regeln durch. Kein anderer Code im Programm kann einen negativen Kontostand erzeugen, egal wie er geschrieben ist. Das bringt Kapselung: Die Regeln stehen an einer Stelle.

private gilt pro Typ, nicht pro Objekt. Eine Methode von Account darf other.balance einer anderen Account-Instanz lesen, so werden Equals und Vergleichsmethoden meist geschrieben.

protected: sichtbar für abgeleitete Klassen

Ein protected-Member ist vor der Außenwelt verborgen, aber für Klassen verfügbar, die von der deklarierenden Klasse erben.

Ausgabe:

Sam: 4000.00
Rita: 6400.00

Eine Regel überrascht Leute. Innerhalb von Manager darfst du baseSalary auf this oder einem anderen Manager verwenden, aber nicht auf einem beliebigen Employee:

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)
    }
}

Der Grund: other könnte ein Contractor sein, der ebenfalls von Employee abgeleitet ist, und protected gewährt Zugriff auf deinen eigenen Zweig der Hierarchie, nicht auf den deiner Geschwister.

Ein geschütztes Feld koppelt jede abgeleitete Klasse für immer an dieses Feld. Viele Codebasen bevorzugen eine protected-Property oder -Methode oder halten Felder privat und geben abgeleiteten Klassen nur, was sie brauchen.

internal: sichtbar innerhalb der Assembly

internal-Member und -Typen können von jedem Code im selben Projekt verwendet werden und von nichts außerhalb. Eine Bibliothek nutzt das für die Hilfsmethoden, auf die sich ihre öffentlichen Klassen stützen:

// 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;
}

Typen auf oberster Ebene sind internal, wenn du keinen Modifizierer schreibst. Deshalb „fehlt“ eine Klasse, die du in einer Klassenbibliothek vergessen hast als public zu markieren, in dem Projekt, das sie referenziert.

Unit-Test-Projekte sind separate Assemblies und können internal-Code daher ebenfalls nicht sehen. Die übliche Lösung ist ein Attribut in der Bibliothek:

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

protected internal und private protected

Diese beiden kombinieren die vorherigen Modifizierer auf entgegengesetzte Weise, und ihre Namen sind leicht zu verwechseln:

  • protected internal ist protected oder internal: jeder Code in derselben Assembly plus abgeleitete Klassen in anderen Assemblies. Es ist der weitere.
  • private protected (C# 7.2) ist protected und internal: nur abgeleitete Klassen, die auch in derselben Assembly liegen. Es ist der engere, für eine Basisklasse, deren Erweiterungspunkte innerhalb deiner Bibliothek bleiben sollen.
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)
}

Standardwerte, wenn du nichts schreibst

WoStandardErlaubt
In einem Namespace deklarierter Typinternalpublic, internal, file (C# 11)
Member einer Klasseprivatealle sechs
Member eines Structsprivatepublic, internal, private (von Structs kann nicht geerbt werden)
Verschachtelter Typprivatealle sechs
Interface-Memberpublicexplizite Modifizierer seit C# 8 erlaubt
Enum-Memberpublickeine

Explizit zu sein kostet ein Wort und erspart dem nächsten Leser eine Frage, deshalb verlangen die meisten Styleguides den Modifizierer auch dann, wenn er dem Standard entspricht.

Zugriff auf Ebene der Accessoren

Eine Property oder ein Indexer kann einem Accessor einen engeren Modifizierer geben als der Property selbst:

Ausgabe:

report.pdf: 100%

Der Modifizierer des Accessors muss restriktiver sein als der der Property, und nur einer der beiden Accessoren darf einen haben.

Inkonsistente Zugreifbarkeit

Ein öffentlicher Member kann keinen Typ offenlegen, der weniger sichtbar ist als er selbst, weil Aufrufer dann etwas bekämen, das sie nicht benennen dürfen:

internal class Discount { }

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

Dieselbe Regel ergibt CS0051 für Parametertypen und CS0053 für Property-Typen. Behebe das, indem du den Typ so sichtbar machst wie den Member oder den Member so verborgen wie den Typ.

Einen Modifizierer wählen

Beginne mit dem restriktivsten Modifizierer, der funktioniert, und erweitere ihn nur, wenn ein Aufrufer es braucht. Etwas später sichtbarer zu machen ist einfach und bricht nie jemanden; etwas weniger sichtbar zu machen bricht jeden Aufrufer, der es verwendet hat. In der Praxis: Felder private, die Member, die den Zweck der Klasse ausmachen, public, Hilfsmethoden private und Typen nur für die Bibliothek internal.

Häufig gestellte Fragen

Welche Zugriffsmodifizierer gibt es in C#?

Es gibt sechs: public (jeder Code), private (nur der enthaltende Typ), protected (der enthaltende Typ und davon abgeleitete Typen), internal (jeder Code in derselben Assembly), protected internal (dieselbe Assembly oder abgeleitete Typen überall) und private protected (abgeleitete Typen in derselben Assembly, C# 7.2). C# 11 hat file für Typen hinzugefügt, die nur in einer Quelldatei sichtbar sind.

Was ist der Standard-Zugriffsmodifizierer in C#?

Member einer Klasse oder eines Structs (Felder, Methoden, Properties, verschachtelte Typen) sind standardmäßig private. Typen auf oberster Ebene (eine direkt in einem Namespace deklarierte Klasse) sind standardmäßig internal. Interface-Member und Enum-Member sind öffentlich.

Was bedeutet protected in C#?

Ein protected-Member ist in seiner eigenen Klasse und in jeder davon abgeleiteten Klasse sichtbar, aber nicht für anderen Code. Eine abgeleitete Klasse kann ihn nur über ihren eigenen Typ verwenden: Innerhalb von Manager funktioniert this.baseSalary, aber auf baseSalary eines beliebigen anderen Employee-Objekts zuzugreifen ist Fehler CS1540.

Was ist internal in C#?

internal macht einen Typ oder Member für allen Code in derselben Assembly sichtbar (der kompilierten .dll oder .exe desselben Projekts) und außerhalb davon unsichtbar. So hält eine Bibliothek Hilfsklassen aus ihrer öffentlichen API heraus. [assembly: InternalsVisibleTo("MyLib.Tests")] macht sie auch für ein Testprojekt sichtbar.

Wie behebe ich „is inaccessible due to its protection level“?

Das ist Fehler CS0122: Der Code verwendet einen Member, den er nicht sehen darf, meist ein Feld, das beim Standard private geblieben ist. Wenn externer Code es lesen soll, stelle eine öffentliche Property oder Methode bereit; mach nicht einfach das Feld öffentlich. Wenn es ein Typ aus einem anderen Projekt ist, ist er wahrscheinlich internal.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S