Partielle Klassen und Methoden (C#-Programmierhandbuch)

Sie können die Definition einer Klasse oder einer Struktur, einer Schnittstelle oder einer Methode auf zwei oder mehr Quelldateien aufteilen. Jede Quelldatei enthält einen Abschnitt der Typ- oder Methodendefinition, und alle Teile werden bei der Kompilierung der Anwendung miteinander kombiniert.

Teilklassen

Es gibt mehrere Situationen, in denen das Teilen einer Klassendefinition von Vorteil sein kann:

  • Beim Arbeiten an großen Projekten ermöglicht das Aufteilen einer Klasse auf verschiedene Dateien mehreren Programmierern, gleichzeitig daran zu arbeiten.

  • Beim Arbeiten mit einer automatisch generierten Quelle kann der Klasse Code hinzugefügt werden, ohne die Quelldatei neu erstellen zu müssen. Visual Studio verwendet diesen Ansatz beim Erstellen von Windows Forms, Webdienst-Wrappercode usw. Dadurch können Sie Code erstellen, der diese Klassen verwendet, ohne die von Visual Studio erstellte Datei ändern zu müssen.

  • Um eine Klassendefinition aufzuteilen, verwenden Sie den Modifizierer des partial-Schlüsselworts, wie im folgenden Beispiel gezeigt:

public partial class Employee
{
    public void DoWork()
    {
    }
}

public partial class Employee
{
    public void GoToLunch()
    {
    }
}

Das partial-Schlüsselwort gibt an, dass weitere Teile der Klasse, Struktur oder Schnittstelle im Namespace definiert werden können. Alle Teile müssen das partial-Schlüsselwort verwenden. Alle Teile müssen beim Kompilieren verfügbar sein, um den Gesamttyp zu bilden. Alle Teile müssen die gleiche Zugriffsebene haben, z. B. public, private usw.

Wenn ein Teil als abstract deklariert ist, dann wird der ganze Typ als abstract betrachtet. Wenn ein Teil als sealed deklariert ist, dann wird der ganze Typ als sealed betrachtet. Wenn ein Teil einen Basistyp deklariert, dann erbt der ganze Typ diese Klasse.

Alle Teile, die eine Basisklasse angeben, müssen übereinstimmen. Auch Teile, die eine Basisklasse weglassen, erben den Basistyp. Teile können unterschiedliche Basisschnittstellen angeben. Der Gesamttyp implementiert alle durch die Teildeklarationen aufgelisteten Schnittstellen. Alle Klassen-, Struktur- oder Schnittstellenmember, die in einer partiellen Definition deklariert sind, stehen allen anderen Teilen zur Verfügung. Der Gesamttyp ist die Kombination aller Teile zur Kompilierzeit.

Tipp

Der partial-Modifizierer ist für Delegat- oder Enumerationsdeklarationen nicht verfügbar.

Das folgende Beispiel zeigt, dass geschachtelte Typen partiell sein können, auch wenn der Typ, in dem sie geschachtelt sind, selbst nicht partiell ist.

class Container
{
    partial class Nested
    {
        void Test() { }
    }
    partial class Nested
    {
        void Test2() { }
    }
}

Zur Kompilierzeit werden die Attribute der partiellen Typdefinitionen zusammengeführt. Betrachten Sie beispielsweise die folgenden Deklarationen:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

Sie entsprechen den folgenden Deklarationen:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

Folgende Elemente werden aus allen Definitionen des partiellen Typs zusammengeführt:

  • XML-Kommentare

  • interfaces

  • Generische Typparameterattribute

  • Klassenattribute

  • Member

Betrachten Sie beispielsweise die folgenden Deklarationen:

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

Sie entsprechen den folgenden Deklarationen:

class Earth : Planet, IRotate, IRevolve { }

Beschränkungen

Beim Arbeiten mit partiellen Klassendefinitionen sind mehrere Regeln zu beachten:

  • Alle partiellen Typdefinitionen, die als Teile des gleichen Typs vorgesehen sind, müssen mit partial bearbeitet werden. Durch folgende Klassendeklarationen wird z. B. ein Fehler verursacht:

    public partial class A { }
    //public class tcA { }  // Error, must also be marked partial
    
  • Der partial-Modifizierer kann nur unmittelbar vor den Schlüsselwörtern class, struct oder interface stehen.

  • Geschachtelte partielle Typen sind in Definitionen des partiellen Typs zulässig, wie im folgenden Beispiel veranschaulicht:

    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Alle partiellen Typdefinitionen, die als Teile desselben Typs vorgesehen sind, müssen in derselben Assembly und demselben Modul (EXE- oder DLL-Datei) definiert sein. Partielle Definitionen können sich nicht über mehrere Module erstrecken.

  • Der Klassenname und die generischen Typparameter müssen in allen partiellen Typdefinitionen übereinstimmen. Generische Typen können partiell sein. Jede partielle Deklaration muss die gleichen Parameternamen in der gleichen Reihenfolge verwenden.

  • Folgende Schlüsselwörter sind in Definitionen für partielle Typen optional. Falls sie aber in einer der partiellen Typdefinitionen vorhanden sind, dürfen sie nicht in Konflikt mit Schlüsselwörtern stehen, die in einer anderen partiellen Definition für denselben Typ angegeben sind:

Beispiel 1

Beschreibungen

Im folgenden Beispiel sind die Felder und der Konstruktor der Klasse, CoOrds, in einer partiellen Klassendefinition deklariert, und der PrintCoOrds-Member ist in einer anderen partiellen Klassendefinition deklariert.

Code

public partial class CoOrds
{
    private int x;
    private int y;

    public CoOrds(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class CoOrds
{
    public void PrintCoOrds()
    {
        Console.WriteLine("CoOrds: {0},{1}", x, y);
    }

}

class TestCoOrds
{
    static void Main()
    {
        CoOrds myCoOrds = new CoOrds(10, 15);
        myCoOrds.PrintCoOrds();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: CoOrds: 10,15

Beispiel 2

Beschreibungen

Das folgende Beispiel zeigt, dass auch partielle Strukturen und Schnittstellen entwickelt werden können.

Code

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

Partielle Methoden

Eine partielle Klasse oder Struktur kann eine partielle Methode enthalten. Ein Teil der Klasse enthält die Signatur der Methode. Eine optionale Implementierung kann im selben oder einem anderen Teil definiert sein. Ist keine Implementierung angegeben, werden die Methode und alle Aufrufe der Methode beim Kompilieren entfernt.

Mit partiellen Methoden kann der Implementierer eines Teils einer Klasse eine Methode definieren, ähnlich wie ein Ereignis. Der Implementierer des anderen Teils der Klasse kann entscheiden, ob die Methode implementiert werden soll oder nicht. Wird die Methode nicht implementiert, entfernt der Compiler die Methodensignatur und alle Aufrufe der Methode. Die Aufrufe der Methode, einschließlich aller Ergebnisse, die bei der Auswertung von Argumenten in Aufrufen auftreten würden, haben keine Auswirkungen während der Laufzeit. So kann jeder Code in der partiellen Klasse eine partielle Methode verwenden, auch wenn die Implementierung nicht bereitgestellt wurde. Es treten weder Kompilier- noch Laufzeitfehler auf, wenn die Methode aufgerufen wird, ohne implementiert zu sein.

Partielle Methoden sind besonders hilfreich, wenn es darum geht, generierten Code anzupassen. Sie ermöglichen das Reservieren eines Methodennamens und einer Signatur, sodass der generierte Code die Methode aufrufen kann und dem Entwickler die Entscheidung überlassen bleibt, die Methode zu implementieren. Ähnlich wie partielle Klassen ermöglichen partielle Methoden, dass vom Code-Generator erstellter Code und vom Entwickler erstellter Code zusammen verwendet werden können, ohne dass Laufzeitkosten entstehen.

Die Deklaration einer partiellen Methode besteht aus zwei Teilen: Definition und Implementierung. Diese können sich in getrennten Teilen einer partiellen Klasse oder im selben Teil befinden. Ohne Implementierungsdeklaration optimiert und entfernt der Compiler sowohl die definierende Deklaration als auch alle Aufrufe der Methode.

// Definition in file1.cs
partial void onNameChanged();

// Implementation in file2.cs
partial void onNameChanged()
{
  // method body
}
  • Die Deklarationen partieller Methoden müssen mit dem kontextbezogenen Schlüsselwort partial beginnen, und die Methode muss void zurückgeben.

  • Partielle Methoden dürfen ref-Parameter, aber keine out-Parameter aufweisen.

  • Partielle Methoden sind implizit private, können also nicht virtual sein.

  • Partielle Methoden dürfen nicht extern sein, da durch das Vorhandensein von Text festgelegt ist, ob sie definierend oder implementierend sind.

  • Partielle Methoden können über Modifizierer vom Typ static und unsafe verfügen.

  • Partielle Methoden können generisch sein. Für die definierende Deklaration einer partiellen Methode gelten Einschränkungen, die optional für die implementierende Deklaration wiederholt werden können. Die Namen von Parametern und Typparametern müssen in der implementierenden und definierenden Deklaration nicht übereinstimmen.

  • Sie können einen Delegaten zu einer partiellen Methode machen, die definiert wurde und implementiert wurde, nicht jedoch zu einer partiellen Methode, die nur definiert wurde.

C#-Programmiersprachenspezifikation

Weitere Informationen finden Sie in der C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.

Siehe auch

Referenz

Klassen (C#-Programmierhandbuch)

Strukturen (C#-Programmierhandbuch)

Schnittstellen (C#-Programmierhandbuch)

partial (Typ) (C#-Referenz)

Konzepte

C#-Programmierhandbuch