Partielle Klassen und Methoden (C#-Programmierhandbuch)

Es ist möglich, die Definition einer Klasse oder einer Struktur, einer Schnittstelle oder einer Methode auf zwei oder mehr Quelldateien aufzuteilen. Jede Quelldatei enthält einen Abschnitt der Typ- oder Methodendefinition. Die Teile werden bei der Kompilierung der Anwendung miteinander kombiniert.

Teilklassen

Es gibt mehrere Situationen, bei denen das Aufteilen einer Klassendefinition wünschenswert ist:

  • Wenn Sie an großen Projekten arbeiten, können durch das Verteilen einer Klasse auf mehrere Dateien mehrere Programmierer gleichzeitig daran arbeiten.

  • Wenn Sie mit automatisch erzeugten Quellen arbeiten, kann Code einer Klasse hinzugefügt werden, ohne die Quelldatei neu zu erstellen. Visual Studio verwendet diesen Ansatz, wenn es Windows Forms, Webdienst-Wrappercode usw. erstellt. Sie können Code erstellen, der diese Klassen verwendet, ohne die von Visual Studio erstellte Datei ändern zu müssen.

  • Um eine Klassendefinition aufzuteilen, verwenden Sie den Schlüsselwortmodifizierer partial, wie hier gezeigt wird:

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

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

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

Wenn ein beliebiger Teil als abstrakt deklariert wird, wird anschließend der ganze Typ als abstrakt betrachtet. Wenn ein beliebiges Teil als versiegelt deklariert wird, wird anschließend der ganze Typ als versiegelt betrachtet. Wenn ein beliebiger Teil einen Basistyp deklariert, erbt der ganze Typ diese Klasse.

Alle Teile, die eine Basisklasse angeben, müssen übereinstimmen, aber Teile, die eine Basisklasse auslassen, erben weiterhin den Basistyp. Teile können unterschiedliche Basisschnittstellen angeben, und der letzte Typ implementiert alle Schnittstellen, die von allen Teildeklarationen aufgeführt sind. Alle Klassen-, Struktur- und Schnittstellenmember, die in einer Teildefinition deklariert wurden, sind für alle anderen Teile verfügbar. Der endgültige Typ besteht aus allen Teilen zur Kompilierzeit.

Hinweis

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

Im folgenden Beispiel wird gezeigt, dass geschachtelte Typen eine Teilausführung sein können, selbst wenn der Typ, in dem sie geschachtelt sind, selbst keine ist.

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

Zur Kompilierzeit werden Attribute von 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 { }

Die folgenden werden aus allen partiellen Typdefinitionen zusammengeführt:

  • XML-Kommentare

  • Schnittstellen

  • Generische Parameterattribute

  • 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

Es sind mehrere Regeln zu beachten, wenn Sie partielle Klassendefinitionen verwenden:

  • Alle partiellen Typdefinitionen, die als Teile des gleichen Typs vorgesehen sind, müssen mit partial geändert werden. Die folgenden Klassendeklarationen erzeugen z.B. einen Fehler:

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

  • Geschachtelte partielle Typen sind in partiellen Typdefinitionen zulässig, wie im folgenden Beispiel dargestellt wird:

    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Alle partiellen Typdefinitionen, die als Teile des gleichen Typs vorgesehen sind, müssen in der gleichen Assembly und demselben Modul (EXE- oder DLL-Datei) definiert werden. Partielle Definitionen können nicht mehrere Module umfassen.

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

  • Die nachfolgenden Schlüsselwörter für eine partielle Typdefinition sind optional, wenn sie aber für eine partielle Definition vorhanden sind, können sie nicht mit anderen Schlüsselwörtern in Konflikt treten, die in anderen partiellen Definitionen desselben Typs angegeben wurden:

Beispiel 1

Beschreibung

Im folgenden Beispiel werden die Felder und der Konstruktor der Klasse (CoOrds) in einer partiellen Klassendefinition deklariert, und der Member (PrintCoOrds) wird 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

Beschreibung

Im folgenden Beispiel wird gezeigt, dass Sie auch partielle Strukturen und Schnittstellen entwickeln 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 gleichen oder in einem anderen Teil definiert werden. Wenn die Implementierung nicht bereitgestellt wird, werden anschließend die Methode sowie alle Aufrufe an die Methode zur Kompilierzeit entfernt.

Mit partiellen Methoden kann der Implementierer des einen Teils einer Klasse eine Methode definieren, die einem Ereignis ähnelt. Der Implementierer des anderen Teils der Klasse kann entscheiden, ob die Methode implementiert wird. Wenn die Methode nicht implementiert wird, kann der Compiler anschließend die Methodensignatur und alle Aufrufe an die Methode entfernen. Die Aufrufe an die Methode, einschließlich Ergebnissen, die bei der Auswertung eines Arguments im Aufruf auftreten würden, haben zur Laufzeit keine Auswirkung. Deshalb kann jeder Code in der partiellen Klasse eine partielle Methode frei verwenden, selbst wenn die Implementation nicht bereitgestellt wird. Es ergeben sich keine Laufzeit- oder Kompilierzeitfehler, wenn die Methode aufgerufen, aber nicht implementiert wird.

Partielle Methoden sind besonders nützlich, um generierten Code anzupassen. Sie ermöglichen, dass Methodenname und -signatur reserviert werden können, sodass generierter Code die Methode aufrufen kann, aber der Entwickler über die Implementierung der Methode entscheiden kann. Wie partielle Klassen ermöglichen partielle Methoden, dass Code, der von einem Codegenerator erstellt wurde, zusammen mit Code, der von einem menschlichen Entwickler erstellt wurde, ohne Laufzeitkosten ausgeführt wird.

Eine partielle Methodendeklaration besteht aus zwei Teilen: der Definition und der Implementierung. Diese können in separaten Teilen einer partiellen Klasse oder im gleichen Teil sein. Wenn es keine Implementierungsdeklaration gibt, optimiert der Compiler anschließend sowohl die definierende Deklaration als auch alle Aufrufe an die Methode.

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

// Implementation in file2.cs  
partial void onNameChanged()  
{  
  // method body  
}  
  • Partielle Methodendeklarationen müssen mit dem Kontextschlüsselwort partial beginnen, und die Methode muss void zurückgeben.

  • Partielle Methoden können ref-Parameter, aber keine out-Parameter besitzen.

  • Partielle Methoden sind implizit privat und können daher nicht virtuell sein.

  • Partielle Methoden können nicht extern sein, da das Vorhandensein des Texts bestimmt, ob sie definierend oder implementierend sind.

  • Partielle Methoden können statische und unsichere Modifizierer besitzen.

  • Partielle Methoden können generisch sein. Einschränkungen gelten für die definierende partielle Methodendeklaration und können optional für die implementierende wiederholt werden. Parameter- und Typparameternamen müssen in der implementierenden und definierenden Deklaration nicht gleich sein.

  • Sie können einen Delegaten für eine partielle Methode erstellen, die definiert und implementiert wurde. Dies geht jedoch nicht für partielle Methoden, die nur definiert wurden.

C#-Programmiersprachenspezifikation

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

Siehe auch

C#-Programmierhandbuch
Klassen
Strukturen
Schnittstellen
partial (Typ)