Gedeeltelijke klassen en methoden (C#-programmeerhandleiding)
Het is mogelijk om de definitie van een klasse, een struct, een interface of een methode over twee of meer bronbestanden te splitsen. Elk bronbestand bevat een sectie van het type of de methodedefinitie en alle onderdelen worden gecombineerd wanneer de toepassing wordt gecompileerd.
Gedeeltelijke klassen
Er zijn verschillende situaties waarin het splitsen van een klassedefinitie wenselijk is:
- Door een klasse over afzonderlijke bestanden te declareren, kunnen meerdere programmeurs er tegelijkertijd aan werken.
- U kunt code toevoegen aan de klasse zonder dat u het bronbestand dat automatisch gegenereerde bron bevat, opnieuw hoeft te maken. Visual Studio maakt gebruik van deze benadering bij het maken van Windows Forms, webservice-wrappercode, enzovoort. U kunt code maken die gebruikmaakt van deze klassen zonder dat u het bestand hoeft te wijzigen dat is gemaakt door Visual Studio.
- Brongeneratoren kunnen extra functionaliteit genereren in een klasse.
Gebruik de gedeeltelijke wijzigingsfunctie voor trefwoorden om een klassedefinitie te splitsen. In de praktijk wordt elke gedeeltelijke klasse doorgaans gedefinieerd in een afzonderlijk bestand, waardoor het eenvoudiger is om de klasse in de loop van de tijd te beheren en uit te breiden.
In het volgende Employee
voorbeeld ziet u hoe de klasse kan worden verdeeld over twee bestanden: Employee_Part1.cs en 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.
Het partial
trefwoord geeft aan dat andere onderdelen van de klasse, struct of interface kunnen worden gedefinieerd in de naamruimte. Alle onderdelen moeten het partial
trefwoord gebruiken. Alle onderdelen moeten tijdens het compileren beschikbaar zijn om het uiteindelijke type te vormen. Alle onderdelen moeten dezelfde toegankelijkheid hebben, zoals public
, private
enzovoort.
Als een deel abstract wordt gedeclareerd, wordt het hele type beschouwd als abstract. Als een deel wordt gedeclareerd als verzegeld, wordt het hele type beschouwd als verzegeld. Als een deel een basistype declareert, neemt het hele type die klasse over.
Alle onderdelen die een basisklasse opgeven, moeten akkoord gaan, maar delen die een basisklasse weglaten, nemen nog steeds het basistype over. Onderdelen kunnen verschillende basisinterfaces opgeven en het uiteindelijke type implementeert alle interfaces die worden vermeld door alle gedeeltelijke declaraties. Alle klasse-, struct- of interfaceleden die in een gedeeltelijke definitie zijn gedeclareerd, zijn beschikbaar voor alle andere onderdelen. Het uiteindelijke type is de combinatie van alle onderdelen tijdens het compileren.
Notitie
De partial
wijzigingsfunctie is niet beschikbaar voor declaraties voor gemachtigden of opsommingen.
In het volgende voorbeeld ziet u dat geneste typen gedeeltelijk kunnen zijn, zelfs als het type waarin ze zijn genest, niet gedeeltelijk zelf is.
class Container
{
partial class Nested
{
void Test() { }
}
partial class Nested
{
void Test2() { }
}
}
Tijdens het compileren worden kenmerken van gedeeltelijke definities samengevoegd. Denk bijvoorbeeld aan de volgende declaraties:
[SerializableAttribute]
partial class Moon { }
[ObsoleteAttribute]
partial class Moon { }
Ze zijn gelijk aan de volgende declaraties:
[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }
Hieronder worden alle gedeeltelijke definities samengevoegd:
- XML-opmerkingen. Als beide declaraties van een gedeeltelijk lid echter opmerkingen bevatten, worden alleen de opmerkingen van het implementatielid opgenomen.
- Interfaces
- parameterkenmerken van het type generic
- klassekenmerken
- leden
Denk bijvoorbeeld aan de volgende declaraties:
partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }
Ze zijn gelijk aan de volgende declaraties:
class Earth : Planet, IRotate, IRevolve { }
Beperkingen
Er zijn verschillende regels die u moet volgen wanneer u werkt met gedeeltelijke klassedefinities:
- Alle gedeeltelijke definities die zijn bedoeld om onderdelen van hetzelfde type te zijn, moeten worden gewijzigd met
partial
. Met de volgende klassedeclaraties wordt bijvoorbeeld een fout gegenereerd:public partial class A { } //public class A { } // Error, must also be marked partial
- De
partial
wijzigingsfunctie kan alleen direct vóór het trefwoordclass
,struct
ofinterface
. - Geneste gedeeltelijke typen zijn toegestaan in definities van gedeeltelijk type, zoals wordt geïllustreerd in het volgende voorbeeld:
partial class ClassWithNestedClass { partial class NestedClass { } } partial class ClassWithNestedClass { partial class NestedClass { } }
- Alle gedeeltelijke definities die zijn bedoeld om onderdelen van hetzelfde type te zijn, moeten worden gedefinieerd in dezelfde assembly en dezelfde module (.exe of .dll bestand). Gedeeltelijke definities kunnen niet meerdere modules omvatten.
- De klassenaam en de algemene parameters moeten overeenkomen met alle definities van het gedeeltelijke type. Algemene typen kunnen gedeeltelijk zijn. Elke gedeeltelijke declaratie moet dezelfde parameternamen in dezelfde volgorde gebruiken.
- De volgende trefwoorden voor een definitie van een gedeeltelijk type zijn optioneel, maar als deze aanwezig zijn op een gedeeltelijke definitie, moet hetzelfde worden opgegeven voor een andere gedeeltelijke definitie voor hetzelfde type:
Zie Beperkingen voor typeparameters voor meer informatie.
Voorbeelden
In het volgende voorbeeld worden de velden en constructor van de Coords
klasse gedeclareerd in één gedeeltelijke klassedefinitie (Coords_Part1.cs
) en wordt de PrintCoords
methode gedeclareerd in een andere gedeeltelijke klassedefinitie (Coords_Part2.cs
). Deze scheiding laat zien hoe gedeeltelijke klassen kunnen worden verdeeld over meerdere bestanden voor eenvoudiger onderhoud.
// 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
In het volgende voorbeeld ziet u dat u ook gedeeltelijke structs en interfaces kunt ontwikkelen.
partial interface ITest
{
void Interface_Test();
}
partial interface ITest
{
void Interface_Test2();
}
partial struct S1
{
void Struct_Test() { }
}
partial struct S1
{
void Struct_Test2() { }
}
Gedeeltelijke leden
Een gedeeltelijke klasse of struct kan een gedeeltelijk lid bevatten. Een deel van de klasse bevat de handtekening van het lid. Een implementatie kan worden gedefinieerd in hetzelfde deel of een ander onderdeel.
Een implementatie is niet vereist voor een gedeeltelijke methode wanneer de handtekening voldoet aan de volgende regels:
- De declaratie bevat geen toegangsaanpassingen. De methode heeft
private
standaard toegang. - Het retourtype is
void
. - Geen van de parameters heeft de
out
wijzigingsfunctie. - De methodedeclaratie kan geen van de volgende modifiers bevatten:
De methode en alle aanroepen naar de methode worden tijdens het compileren verwijderd wanneer er geen implementatie is.
Elke methode die niet voldoet aan al deze beperkingen, inclusief eigenschappen en indexeerfuncties, moet een implementatie bieden. Deze implementatie kan worden geleverd door een brongenerator. Gedeeltelijke eigenschappen kunnen niet worden geïmplementeerd met behulp van automatisch geïmplementeerde eigenschappen. De compiler kan geen onderscheid maken tussen een automatisch geïmplementeerde eigenschap en de declaratie van een gedeeltelijke eigenschap.
Met gedeeltelijke methoden kan de implementeerfunctie van één deel van een klasse een lid declareren. De implementeerfunctie van een ander deel van de klasse kan dat lid definiëren. Er zijn twee scenario's waarin deze scheiding nuttig is: sjablonen die standaardcode genereren en brongeneratoren.
- Sjablooncode: De sjabloon reserveert een methodenaam en handtekening, zodat gegenereerde code de methode kan aanroepen. Deze methoden volgen de beperkingen waarmee een ontwikkelaar kan bepalen of de methode moet worden geïmplementeerd. Als de methode niet is geïmplementeerd, verwijdert de compiler de handtekening van de methode en alle aanroepen naar de methode. De aanroepen naar de methode, met inbegrip van eventuele resultaten van de evaluatie van argumenten in de aanroepen, hebben geen effect tijdens runtime. Daarom kan elke code in de gedeeltelijke klasse vrijelijk een gedeeltelijke methode gebruiken, zelfs als de implementatie niet wordt geleverd. Er zijn geen compileer- of runtimefouten als de methode wordt aangeroepen, maar niet is geïmplementeerd.
- Brongeneratoren: Brongeneratoren bieden een implementatie voor leden. De menselijke ontwikkelaar kan de liddeclaratie toevoegen (vaak met kenmerken die door de brongenerator worden gelezen). De ontwikkelaar kan code schrijven die deze leden aanroept. De brongenerator wordt uitgevoerd tijdens de compilatie en levert de implementatie. In dit scenario worden de beperkingen voor gedeeltelijke leden die mogelijk niet worden geïmplementeerd, vaak niet gevolgd.
// Definition in file1.cs
partial void OnNameChanged();
// Implementation in file2.cs
partial void OnNameChanged()
{
// method body
}
- Gedeeltelijke liddeclaraties moeten beginnen met het contextuele trefwoord gedeeltelijk.
- Gedeeltelijke lidhandtekeningen in beide delen van het gedeeltelijke type moeten overeenkomen.
- Gedeeltelijk lid kan statische en onveilige modifiers hebben.
- Gedeeltelijk lid kan algemeen zijn. Beperkingen moeten hetzelfde zijn voor de declaratie van de definitie- en implementatiemethode. Parameter- en typeparameternamen hoeven niet hetzelfde te zijn in de implementatiedeclaratie als in het definiëren van de declaratie.
- U kunt een gedelegeerde maken voor een gedeeltelijke methode die is gedefinieerd en geïmplementeerd, maar niet voor een gedeeltelijke methode die geen implementatie heeft.
C#-taalspecificatie
Zie Gedeeltelijke typen en Gedeeltelijke methoden in de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik. De extra functies voor gedeeltelijke methoden worden gedefinieerd in de functiespecificatie.