Partiella klasser och metoder (C#-programmeringsguide)

Det går att dela upp definitionen av en klass, en struct, ett gränssnitt eller en metod över två eller flera källfiler. Varje källfil innehåller ett avsnitt av typen eller metoddefinitionen, och alla delar kombineras när programmet kompileras.

Partiella klasser

Det finns flera situationer när det är önskvärt att dela upp en klassdefinition:

  • Om du deklarerar en klass över separata filer kan flera programmerare arbeta med den samtidigt.
  • Du kan lägga till kod i klassen utan att behöva återskapa källfilen som innehåller automatiskt genererad källa. Visual Studio använder den här metoden när den skapar Windows Forms, webbtjänstomslutningskod och så vidare. Du kan skapa kod som använder dessa klasser utan att behöva ändra filen som skapats av Visual Studio.
  • Källgeneratorer kan generera extra funktioner i en klass.

Om du vill dela upp en klassdefinition använder du den partiella nyckelordsmodifieraren. I praktiken definieras varje partiell klass vanligtvis i en separat fil, vilket gör det enklare att hantera och expandera klassen över tid.

I följande Employee exempel visas hur klassen kan delas upp i två filer: Employee_Part1.cs och Employee_Part2.cs.

// This is in Employee_Part1.cs
public partial class Employee
{
    public void DoWork()
    {
    }
}

// This is in Employee_Part2.cs
public partial class Employee
{
    public void GoToLunch()
    {
    }
}

//Main program demonstrating the Employee class usage
public class Program
{
    public static void Main()
    {
        Employee emp = new Employee();
        emp.DoWork();
        emp.GoToLunch();
    }
}

// Expected Output:
// Employee is working.
// Employee is at lunch.

Nyckelordet partial anger att andra delar av klassen, struct eller gränssnittet kan definieras i namnområdet. Alla delar måste använda nyckelordet partial . Alla delar måste vara tillgängliga vid kompileringstillfället för att bilda den slutliga typen. Alla delar måste ha samma hjälpmedel, till exempel public, privateoch så vidare.

Om någon del förklaras abstrakt anses hela typen vara abstrakt. Om någon del förklaras förseglad anses hela typen vara förseglad. Om någon del deklarerar en bastyp ärver hela typen den klassen.

Alla delar som anger en basklass måste överensstämma, men delar som utelämnar en basklass ärver fortfarande bastypen. Delar kan ange olika basgränssnitt och den slutliga typen implementerar alla gränssnitt som anges av alla partiella deklarationer. Alla klass-, struct- eller gränssnittsmedlemmar som deklareras i en partiell definition är tillgängliga för alla andra delar. Den sista typen är kombinationen av alla delar vid kompileringstiden.

Kommentar

Modifieraren partial är inte tillgänglig för ombuds- eller uppräkningsdeklarationer.

I följande exempel visas att kapslade typer kan vara partiella, även om typen de är kapslade i inte är delvis.

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

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

Vid kompileringstillfället sammanfogas attribut för definitioner av partiell typ. Tänk till exempel på följande deklarationer:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

De motsvarar följande deklarationer:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

Följande sammanfogas från alla definitioner av partiell typ:

  • XML-kommentarer. Men om båda förklaringarna från en delmedlem innehåller kommentarer inkluderas endast kommentarer från den implementerande medlemmen.
  • Gränssnitt
  • parameterattribut av generisk typ
  • klassattribut
  • medlemmar

Tänk till exempel på följande deklarationer:

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

De motsvarar följande deklarationer:

class Earth : Planet, IRotate, IRevolve { }

Begränsningar

Det finns flera regler att följa när du arbetar med partiella klassdefinitioner:

  • Alla definitioner av partiell typ som är avsedda att vara delar av samma typ måste ändras med partial. Följande klassdeklarationer genererar till exempel ett fel:
    public partial class A { }
    //public class A { }  // Error, must also be marked partial
    
  • Modifieraren partial kan bara visas omedelbart före nyckelordet class, structeller interface.
  • Kapslade partiella typer tillåts i definitioner av partiell typ enligt följande exempel:
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Alla definitioner av partiell typ som är avsedda att vara delar av samma typ måste definieras i samma sammansättning och samma modul (.exe eller .dll fil). Partiella definitioner kan inte sträcka sig över flera moduler.
  • Klassnamnet och parametrarna för generisk typ måste matcha alla definitioner av partiell typ. Generiska typer kan vara partiella. Varje partiell deklaration måste använda samma parameternamn i samma ordning.
  • Följande nyckelord i en definition av partiell typ är valfria, men om de finns i en definition av partiell typ måste samma anges för annan partiell definition för samma typ:

Mer information finns i Begränsningar för typparametrar.

Exempel

I följande exempel deklareras fälten och konstruktorn för Coords klassen i en partiell klassdefinition (Coords_Part1.cs), och PrintCoords metoden deklareras i en annan partiell klassdefinition (Coords_Part2.cs). Den här separationen visar hur partiella klasser kan delas upp i flera filer för enklare underhåll.

 // This is in Coords_Part1.cs
 public partial class Coords
 {
     private int x;
     private int y;

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

 // This is in Coords_Part2.cs
 public partial class Coords
 {
     public void PrintCoords()
     {
         Console.WriteLine("Coords: {0},{1}", x, y);
     }
 }

// Main program demonstrating the Coords class usage
 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

I följande exempel visas att du också kan utveckla partiella structs och gränssnitt.

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

Partiella medlemmar

En partiell klass eller struct kan innehålla en partiell medlem. En del av klassen innehåller medlemmens signatur. En implementering kan definieras i samma del eller i en annan del.

En implementering krävs inte för en partiell metod när signaturen följer följande regler:

  • Deklarationen innehåller inga åtkomstmodifierare. Metoden har private åtkomst som standard.
  • Returtypen är void.
  • Ingen av parametrarna har out modifieraren.
  • Metoddeklarationen kan inte innehålla någon av följande modifierare:

Metoden och alla anrop till metoden tas bort vid kompileringstillfället när det inte finns någon implementering.

Alla metoder som inte följer alla dessa begränsningar, inklusive egenskaper och indexerare, måste tillhandahålla en implementering. Implementeringen kan tillhandahållas av en källgenerator. Partiella egenskaper kan inte implementeras med hjälp av automatiskt implementerade egenskaper. Kompilatorn kan inte skilja mellan en automatiskt implementerad egenskap och deklareringsdeklarationen för en partiell egenskap.

Med partiella metoder kan implementeraren av en del av en klass deklarera en medlem. Implementeraren för en annan del av klassen kan definiera den medlemmen. Det finns två scenarier där den här separationen är användbar: mallar som genererar pannplåtskod och källgeneratorer.

  • Mallkod: Mallen reserverar ett metodnamn och en signatur så att genererad kod kan anropa metoden. Dessa metoder följer de begränsningar som gör det möjligt för en utvecklare att bestämma om metoden ska implementeras. Om metoden inte implementeras tar kompilatorn bort metodsignaturen och alla anrop till metoden. Anropen till metoden, inklusive resultat som skulle uppstå vid utvärdering av argument i anropen, har ingen effekt vid körning. Därför kan all kod i den partiella klassen fritt använda en partiell metod, även om implementeringen inte tillhandahålls. Inga kompilerings- eller körningsfel resulterar om metoden anropas men inte implementeras.
  • Källgeneratorer: Källgeneratorer tillhandahåller en implementering för medlemmar. Den mänskliga utvecklaren kan lägga till medlemsdeklarationen (ofta med attribut som läse av källgeneratorn). Utvecklaren kan skriva kod som anropar dessa medlemmar. Källgeneratorn körs under kompileringen och tillhandahåller implementeringen. I det här scenariot följs inte begränsningarna för partiella medlemmar som kanske inte implementeras ofta.
// Definition in file1.cs
partial void OnNameChanged();

// Implementation in file2.cs
partial void OnNameChanged()
{
  // method body
}
  • Partiella medlemsdeklarationer måste börja med det partiella kontextuella nyckelordet.
  • Partiella medlemssignaturer i båda delarna av den partiella typen måste matcha.
  • Partiell medlem kan ha statiska och osäkra modifierare.
  • Partiell medlem kan vara allmän. Begränsningar måste vara desamma för att definiera och implementera metoddeklarationen. Parameter- och typparameternamn behöver inte vara samma i implementeringsdeklarationen som i den definierande.
  • Du kan göra ett ombud till en partiell metod som definierats och implementerats, men inte till en partiell metod som inte har någon implementering.

Språkspecifikation för C#

Mer information finns i Partiella typer och Partiella metoder i C#-språkspecifikationen. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning. De ytterligare funktionerna för partiella metoder definieras i funktionsspecifikationen.

Se även