Records (C#-verwijzing)
U gebruikt de record
wijzigingsfunctie om een referentietype te definiëren dat ingebouwde functionaliteit biedt voor het inkapselen van gegevens. Met C# 10 kan de record class
syntaxis als synoniem een verwijzingstype verduidelijken en record struct
een waardetype definiëren met vergelijkbare functionaliteit.
Wanneer u een primaire constructor voor een record declareert, genereert de compiler openbare eigenschappen voor de primaire constructorparameters. De primaire constructorparameters voor een record worden positionele parameters genoemd. De compiler maakt positionele eigenschappen die de primaire constructor of positionele parameters spiegelen. De compilersynthetiseert geen eigenschappen voor primaire constructorparameters voor typen die de record
wijzigingsfunctie niet hebben.
In de volgende twee voorbeelden worden referentietypen (ofrecord class
) gedemonstreert record
:
public record Person(string FirstName, string LastName);
public record Person
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
};
In de volgende twee voorbeelden ziet u record struct
waardetypen:
public readonly record struct Point(double X, double Y, double Z);
public record struct Point
{
public double X { get; init; }
public double Y { get; init; }
public double Z { get; init; }
}
U kunt ook records maken met onveranderbare eigenschappen en velden:
public record Person
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
};
Recordstructs kunnen ook veranderlijk zijn, zowel positionele recordstructs als recordstructs zonder positionele parameters:
public record struct DataMeasurement(DateTime TakenAt, double Measurement);
public record struct Point
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
Hoewel records kunnen worden gedempt, zijn ze voornamelijk bedoeld voor het ondersteunen van onveranderbare gegevensmodellen. Het recordtype biedt de volgende functies:
- Beknopte syntaxis voor het maken van een verwijzingstype met onveranderbare eigenschappen
- Ingebouwd gedrag handig voor een gegevensgericht verwijzingstype:
- Ondersteuning voor overnamehiërarchieën
In de voorgaande voorbeelden ziet u een aantal onderscheid tussen records die verwijzingstypen en records zijn die waardetypen zijn:
- A
record
of arecord class
declareert een verwijzingstype. Hetclass
trefwoord is optioneel, maar kan duidelijkheid voor lezers toevoegen. Arecord struct
declareert een waardetype. - Positionele eigenschappen zijn onveranderbaar in een
record class
en eenreadonly record struct
. Ze zijn veranderlijk in eenrecord struct
.
In de rest van dit artikel worden beide record class
en record struct
typen besproken. De verschillen worden in elke sectie beschreven. U moet beslissen tussen een record class
en een record struct
vergelijkbaar met het kiezen tussen een class
en een struct
. De termrecord wordt gebruikt om gedrag te beschrijven dat van toepassing is op alle recordtypen. record class
Of record struct
wordt gebruikt om gedrag te beschrijven dat alleen van toepassing is op respectievelijk struct- of klassetypen. Het record struct
type is geïntroduceerd in C# 10.
Positionele syntaxis voor eigenschapsdefinitie
U kunt positionele parameters gebruiken om eigenschappen van een record te declareren en de eigenschapswaarden te initialiseren wanneer u een exemplaar maakt:
public record Person(string FirstName, string LastName);
public static void Main()
{
Person person = new("Nancy", "Davolio");
Console.WriteLine(person);
// output: Person { FirstName = Nancy, LastName = Davolio }
}
Wanneer u de positionele syntaxis voor eigenschapsdefinitie gebruikt, maakt de compiler het volgende:
- Een openbare, automatisch geïmplementeerde eigenschap voor elke positionele parameter die is opgegeven in de recorddeclaratie.
- Voor
record
typen enreadonly record struct
typen: een eigenschap die alleen init is. - Voor
record struct
typen: een eigenschap lezen/schrijven.
- Voor
- Een primaire constructor waarvan de parameters overeenkomen met de positionele parameters in de recorddeclaratie.
- Voor recordstructtypen stelt een parameterloze constructor elk veld in op de standaardwaarde.
- Een
Deconstruct
methode met eenout
parameter voor elke positionele parameter die is opgegeven in de recorddeclaratie. Met de methode worden eigenschappen gedeconstrueerd die zijn gedefinieerd met behulp van positionele syntaxis; hiermee worden eigenschappen genegeerd die zijn gedefinieerd met behulp van de standaardeigenschapsyntaxis.
U kunt kenmerken toevoegen aan een van deze elementen die de compiler maakt op basis van de recorddefinitie. U kunt een doel toevoegen aan elk kenmerk dat u toepast op de eigenschappen van de positionele record. In het volgende voorbeeld wordt de System.Text.Json.Serialization.JsonPropertyNameAttribute toepassing toegepast op elke eigenschap van de Person
record. Het property:
doel geeft aan dat het kenmerk wordt toegepast op de door de compiler gegenereerde eigenschap. Andere waarden zijn field:
om het kenmerk toe te passen op het veld en param:
om het kenmerk toe te passen op de parameter.
/// <summary>
/// Person record type
/// </summary>
/// <param name="FirstName">First Name</param>
/// <param name="LastName">Last Name</param>
/// <remarks>
/// The person type is a positional record containing the
/// properties for the first and last name. Those properties
/// map to the JSON elements "firstName" and "lastName" when
/// serialized or deserialized.
/// </remarks>
public record Person([property: JsonPropertyName("firstName")] string FirstName,
[property: JsonPropertyName("lastName")] string LastName);
In het voorgaande voorbeeld ziet u ook hoe u xml-documentatieopmerkingen voor de record maakt. U kunt de <param>
tag toevoegen om documentatie toe te voegen voor de parameters van de primaire constructor.
Als de gegenereerde definitie van de automatisch geïmplementeerde eigenschap niet is wat u wilt, kunt u uw eigen eigenschap van dezelfde naam definiëren. U kunt bijvoorbeeld de toegankelijkheid of de mutabiliteit wijzigen of een implementatie bieden voor de get
of set
accessor. Als u de eigenschap in uw bron declareert, moet u deze initialiseren vanuit de positionele parameter van de record. Als uw eigenschap een automatisch geïmplementeerde eigenschap is, moet u de eigenschap initialiseren. Als u een back-upveld aan uw bron toevoegt, moet u het back-upveld initialiseren. De gegenereerde deconstructor maakt gebruik van uw eigenschapsdefinitie. In het volgende voorbeeld worden bijvoorbeeld de FirstName
en LastName
eigenschappen van een positionele record public
declareren, maar wordt de Id
positionele parameter beperkt tot internal
. U kunt deze syntaxis gebruiken voor records en recordstructtypen.
public record Person(string FirstName, string LastName, string Id)
{
internal string Id { get; init; } = Id;
}
public static void Main()
{
Person person = new("Nancy", "Davolio", "12345");
Console.WriteLine(person.FirstName); //output: Nancy
}
Een recordtype hoeft geen positionele eigenschappen te declareren. U kunt een record zonder positionele eigenschappen declareren en u kunt andere velden en eigenschappen declareren, zoals in het volgende voorbeeld:
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; } = [];
};
Als u eigenschappen definieert met behulp van de standaardeigenschapsyntaxis, maar de toegangsaanpassing weglaat, zijn de eigenschappen impliciet private
.
Onveranderbaarheid
Een positionele record en een positionele alleen-lezen record struct declareren alleen-init-eigenschappen. Een positionele recordstruct declareert eigenschappen voor lezen/schrijven. U kunt een van deze standaardwaarden overschrijven, zoals wordt weergegeven in de vorige sectie.
Onveranderbaarheid kan handig zijn wanneer u een gegevensgericht type nodig hebt om thread-veilig te zijn of als u afhankelijk bent van een hash-code die hetzelfde blijft in een hash-tabel. Onveranderbaarheid is echter niet geschikt voor alle gegevensscenario's. Entity Framework Core biedt bijvoorbeeld geen ondersteuning voor het bijwerken met onveranderbare entiteitstypen.
Eigenschappen die alleen init zijn, ongeacht of ze zijn gemaakt op basis van positionele parameters (record class
en readonly record struct
) of door accessors op te geven init
, hebben ondiepe onveranderbaarheid. Na de initialisatie kunt u de waarde van eigenschappen van het waardetype of de verwijzing naar eigenschappen van het verwijzingstype niet wijzigen. De gegevens waarnaar een verwijzingstypeeigenschap verwijst, kunnen echter worden gewijzigd. In het volgende voorbeeld ziet u dat de inhoud van een onveranderbare eigenschap (in dit geval een matrix) onveranderbaar is:
public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static void Main()
{
Person person = new("Nancy", "Davolio", new string[1] { "555-1234" });
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-1234
person.PhoneNumbers[0] = "555-6789";
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-6789
}
De functies die uniek zijn voor recordtypen worden geïmplementeerd door compiler-gesynthetiseerde methoden en geen van deze methoden is onveranderbaar door objectstatus te wijzigen. Tenzij opgegeven, worden de gesynthetiseerde methoden gegenereerd voor record
, record struct
en readonly record struct
declaraties.
Gelijkheid van waarde
Als u gelijkheidsmethoden niet overschrijft of vervangt, bepaalt het type dat u declareert hoe gelijkheid wordt gedefinieerd:
- Voor
class
typen zijn twee objecten gelijk als ze verwijzen naar hetzelfde object in het geheugen. - Voor
struct
typen zijn twee objecten gelijk als ze van hetzelfde type zijn en dezelfde waarden opslaan. - Voor typen met de
record
wijzigingsfunctie (record class
,record struct
enreadonly record struct
) zijn twee objecten gelijk als ze van hetzelfde type zijn en dezelfde waarden opslaan.
De definitie van gelijkheid voor een record struct
is hetzelfde als voor een struct
. Het verschil is dat voor een struct
, de implementatie zich bevindt ValueType.Equals(Object) en afhankelijk is van reflectie. Voor records wordt de implementatie gesynthetiseerd en worden de gedeclareerde gegevensleden gebruikt.
Referentie-gelijkheid is vereist voor sommige gegevensmodellen. Entity Framework Core is bijvoorbeeld afhankelijk van gelijkheid van verwijzingen om ervoor te zorgen dat er slechts één exemplaar van een entiteitstype wordt gebruikt voor wat conceptueel één entiteit is. Daarom zijn records en recordstructs niet geschikt voor gebruik als entiteitstypen in Entity Framework Core.
In het volgende voorbeeld ziet u de gelijkheid van waarden van recordtypen:
public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static void Main()
{
var phoneNumbers = new string[2];
Person person1 = new("Nancy", "Davolio", phoneNumbers);
Person person2 = new("Nancy", "Davolio", phoneNumbers);
Console.WriteLine(person1 == person2); // output: True
person1.PhoneNumbers[0] = "555-1234";
Console.WriteLine(person1 == person2); // output: True
Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
}
Om gelijkheid van waarden te implementeren,synthetiseert de compiler verschillende methoden, waaronder:
Een onderdrukking van Object.Equals(Object). Dit is een fout als de onderdrukking expliciet wordt gedeclareerd.
Deze methode wordt gebruikt als basis voor de Object.Equals(Object, Object) statische methode wanneer beide parameters niet null zijn.
A
virtual
, ofsealed
,Equals(R? other)
waarR
is het recordtype. Met deze methode wordt geïmplementeerd IEquatable<T>. Deze methode kan expliciet worden gedeclareerd.Als het recordtype is afgeleid van een basisrecordtype
Base
,Equals(Base? other)
. Dit is een fout als de onderdrukking expliciet wordt gedeclareerd. Als u uw eigen implementatie vanEquals(R? other)
, geef dan ook een implementatie vanGetHashCode
.Een onderdrukking van Object.GetHashCode(). Deze methode kan expliciet worden gedeclareerd.
Onderdrukkingen van operators
==
en!=
. Dit is een fout als de operators expliciet worden gedeclareerd.Als het recordtype is afgeleid van een basisrecordtype,
protected override Type EqualityContract { get; };
. Deze eigenschap kan expliciet worden gedeclareerd. Zie Gelijkheid in overnamehiërarchieën voor meer informatie.
De compiler maakt geen methode wanneer een recordtype een methode heeft die overeenkomt met de handtekening van een gesynthetiseerde methode die expliciet kan worden gedeclareerd.
Niet-destructieve mutatie
Als u een exemplaar met enkele wijzigingen wilt kopiëren, kunt u een expressie gebruiken om een with
niet-destructieve mutatie te bereiken. Een with
expressie maakt een nieuw recordexemplaar dat een kopie is van een bestaand recordexemplaar, met opgegeven eigenschappen en velden gewijzigd. U gebruikt de syntaxis van de object-initialisatiefunctie om de waarden op te geven die moeten worden gewijzigd, zoals wordt weergegeven in het volgende voorbeeld:
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; }
}
public static void Main()
{
Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
Console.WriteLine(person1);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Person person2 = person1 with { FirstName = "John" };
Console.WriteLine(person2);
// output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { PhoneNumbers = new string[1] };
Console.WriteLine(person2);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { };
Console.WriteLine(person1 == person2); // output: True
}
De with
expressie kan positionele eigenschappen of eigenschappen instellen die zijn gemaakt met behulp van de standaardeigenschapsyntaxis. Expliciet gedeclareerde eigenschappen moeten een init
of set
accessor hebben die moet worden gewijzigd in een with
expressie.
Het resultaat van een with
expressie is een ondiepe kopie, wat betekent dat voor een verwijzingseigenschap alleen de verwijzing naar een exemplaar wordt gekopieerd. Zowel de oorspronkelijke record als de kopie eindigen met een verwijzing naar hetzelfde exemplaar.
Als u deze functie voor record class
typen wilt implementeren,synthetiseert de compiler een kloonmethode en een kopieerconstructor. De virtuele kloonmethode retourneert een nieuwe record die is geïnitialiseerd door de kopieerconstructor. Wanneer u een with
expressie gebruikt, maakt de compiler code die de kloonmethode aanroept en stelt de eigenschappen in die zijn opgegeven in de with
expressie.
Als u een ander kopieergedrag nodig hebt, kunt u uw eigen kopieerconstructor schrijven in een record class
. Als u dat doet, wordt er geen synthetiseren door de compiler. Maak uw constructor private
als de record is sealed
, anders maken protected
. De compilersynthetiseert geen kopieerconstructor voor record struct
typen. U kunt er een schrijven, maar de compiler genereert er geen aanroepen naar voor with
expressies. De waarden van de opdracht record struct
worden gekopieerd.
U kunt de kloonmethode niet overschrijven en u kunt geen lid met de naam Clone
van een recordtype maken. De werkelijke naam van de kloonmethode wordt gegenereerd door een compiler.
Ingebouwde opmaak voor weergave
Recordtypen hebben een door compiler gegenereerde ToString methode waarmee de namen en waarden van openbare eigenschappen en velden worden weergegeven. De ToString
methode retourneert een tekenreeks met de volgende indeling:
<recordtypenaam { <eigenschapsnaam>> = <waarde>, <eigenschapsnaam> = <waarde>, ...}
De tekenreeks die wordt <value>
afgedrukt, is de tekenreeks die wordt geretourneerd door het ToString() type eigenschap. In het volgende voorbeeld ChildNames
is een System.Array, waarbij ToString
wordt System.String[]
geretourneerd:
Person { FirstName = Nancy, LastName = Davolio, ChildNames = System.String[] }
Als u deze functie wilt implementeren, worden in record class
typen een virtuele PrintMembers
methode en een ToString onderdrukking door de compiler gesynthetiseert. In record struct
typen is private
dit lid .
Met ToString
de onderdrukking wordt een StringBuilder object gemaakt met de typenaam gevolgd door een vierkante haak openen. Er wordt aanroepen PrintMembers
om eigenschapsnamen en -waarden toe te voegen en vervolgens de vierkante haak sluiten toe te voegen. In het volgende voorbeeld ziet u code die lijkt op wat de gesynthetiseerde onderdrukking bevat:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Teacher"); // type name
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}
U kunt uw eigen implementatie van PrintMembers
of de ToString
onderdrukking opgeven. Verderop in dit artikel vindt u voorbeelden in de opmaak in de PrintMembers
sectie afgeleide records . In C# 10 en hoger kan uw implementatie ToString
de sealed
wijzigingsfunctie bevatten, waardoor de compiler geen ToString
implementatie voor afgeleide records kan synthetiseren. U kunt een consistente tekenreeksweergave maken in een hiërarchie van record
typen. (Afgeleide records hebben nog steeds een PrintMembers
methode gegenereerd voor alle afgeleide eigenschappen.)
Overname
Deze sectie is alleen van toepassing op record class
typen.
Een record kan overnemen van een andere record. Een record kan echter niet overnemen van een klasse en een klasse kan niet overnemen van een record.
Positionele parameters in afgeleide recordtypen
De afgeleide record declareert positionele parameters voor alle parameters in de primaire constructor van de basisrecord. De basisrecord declareert en initialiseert deze eigenschappen. De afgeleide record verbergt ze niet, maar maakt en initialiseert alleen eigenschappen voor parameters die niet zijn gedeclareerd in de basisrecord.
In het volgende voorbeeld ziet u de overname met de syntaxis van de positionele eigenschap:
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
Gelijkheid in overnamehiërarchieën
Deze sectie is van toepassing op record class
typen, maar niet op record struct
typen. Als u wilt dat twee recordvariabelen gelijk zijn, moet het uitvoeringstijdtype gelijk zijn. De typen met variabelen kunnen verschillen. Overgenomen gelijkheidsvergelijking wordt geïllustreerd in het volgende codevoorbeeld:
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Person student = new Student("Nancy", "Davolio", 3);
Console.WriteLine(teacher == student); // output: False
Student student2 = new Student("Nancy", "Davolio", 3);
Console.WriteLine(student2 == student); // output: True
}
In het voorbeeld worden alle variabelen gedeclareerd als Person
, zelfs wanneer het exemplaar een afgeleid type is van of Student
Teacher
. De exemplaren hebben dezelfde eigenschappen en dezelfde eigenschapswaarden. Maar student == teacher
retourneert False
hoewel beide -type variabelen zijn Person
en student == student2
retourneert True
hoewel één een Person
variabele is en één een Student
variabele is. De gelijkheidstest is afhankelijk van het runtime-type van het werkelijke object, niet het gedeclareerde type van de variabele.
Om dit gedrag te implementeren,synthetiseert de compiler een EqualityContract
eigenschap die een Type object retourneert dat overeenkomt met het type record. Hiermee EqualityContract
kunnen de gelijkheidsmethoden het runtimetype objecten vergelijken wanneer ze controleren op gelijkheid. Als het basistype van een record is, is object
virtual
deze eigenschap . Als het basistype een ander recordtype is, is deze eigenschap een onderdrukking. Als het recordtype is, is sealed
deze eigenschap effectief sealed
omdat het type is sealed
.
Wanneer code twee exemplaren van een afgeleid type vergelijkt, controleren de gesynthetiseerde gelijkheidsmethoden alle gegevensleden van de basis en afgeleide typen op gelijkheid. De gesynthetiseerde GetHashCode
methode maakt gebruik van de GetHashCode
methode van alle gegevensleden die zijn gedeclareerd in het basistype en het afgeleide recordtype. De gegevensleden van een record
omvatten alle gedeclareerde velden en het gecompileerde back-upveld voor alle automatisch geïmplementeerde eigenschappen.
with
expressies in afgeleide records
Het resultaat van een with
expressie heeft hetzelfde runtimetype als de operand van de expressie. Alle eigenschappen van het runtimetype worden gekopieerd, maar u kunt alleen eigenschappen van het type compileertijd instellen, zoals in het volgende voorbeeld wordt weergegeven:
public record Point(int X, int Y)
{
public int Zbase { get; set; }
};
public record NamedPoint(string Name, int X, int Y) : Point(X, Y)
{
public int Zderived { get; set; }
};
public static void Main()
{
Point p1 = new NamedPoint("A", 1, 2) { Zbase = 3, Zderived = 4 };
Point p2 = p1 with { X = 5, Y = 6, Zbase = 7 }; // Can't set Name or Zderived
Console.WriteLine(p2 is NamedPoint); // output: True
Console.WriteLine(p2);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = A, Zderived = 4 }
Point p3 = (NamedPoint)p1 with { Name = "B", X = 5, Y = 6, Zbase = 7, Zderived = 8 };
Console.WriteLine(p3);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = B, Zderived = 8 }
}
PrintMembers
opmaak in afgeleide records
De gesynthetiseerde PrintMembers
methode van een afgeleid recordtype roept de basis-implementatie aan. Het resultaat is dat alle openbare eigenschappen en velden van zowel afgeleide als basistypen zijn opgenomen in de ToString
uitvoer, zoals wordt weergegeven in het volgende voorbeeld:
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
U kunt uw eigen implementatie van de PrintMembers
methode bieden. Als u dit doet, gebruikt u de volgende handtekening:
- Voor een
sealed
record die is afgeleid vanobject
(declareert geen basisrecord):private bool PrintMembers(StringBuilder builder)
- Voor een record die is afgeleid van een
sealed
andere record (let op: het insluittype issealed
, dus de methode is effectiefsealed
):protected override bool PrintMembers(StringBuilder builder)
- Voor een record die niet
sealed
is en is afgeleid van object:protected virtual bool PrintMembers(StringBuilder builder);
- Voor een record die niet
sealed
is en is afgeleid van een andere record:protected override bool PrintMembers(StringBuilder builder);
Hier volgt een voorbeeld van code die de gesynthetiseerde PrintMembers
methoden vervangt, een voor een recordtype dat is afgeleid van een object en een voor een recordtype dat is afgeleid van een andere record:
public abstract record Person(string FirstName, string LastName, string[] PhoneNumbers)
{
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"FirstName = {FirstName}, LastName = {LastName}, ");
stringBuilder.Append($"PhoneNumber1 = {PhoneNumbers[0]}, PhoneNumber2 = {PhoneNumbers[1]}");
return true;
}
}
public record Teacher(string FirstName, string LastName, string[] PhoneNumbers, int Grade)
: Person(FirstName, LastName, PhoneNumbers)
{
protected override bool PrintMembers(StringBuilder stringBuilder)
{
if (base.PrintMembers(stringBuilder))
{
stringBuilder.Append(", ");
};
stringBuilder.Append($"Grade = {Grade}");
return true;
}
};
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", new string[2] { "555-1234", "555-6789" }, 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, PhoneNumber1 = 555-1234, PhoneNumber2 = 555-6789, Grade = 3 }
}
Notitie
In C# 10 en hoger wordt de compiler gesynthetiseert PrintMembers
in afgeleide records, zelfs wanneer een basisrecord de ToString
methode heeft verzegeld. U kunt ook uw eigen implementatie van PrintMembers
.
Gedrag van deconstructor in afgeleide records
De Deconstruct
methode van een afgeleide record retourneert de waarden van alle positionele eigenschappen van het type compileertijd. Als het variabeletype een basisrecord is, worden alleen de eigenschappen van de basisrecord gedeconstrueerd, tenzij het object naar het afgeleide type wordt gecast. In het volgende voorbeeld ziet u hoe u een deconstructor aanroept voor een afgeleide record.
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
var (firstName, lastName) = teacher; // Doesn't deconstruct Grade
Console.WriteLine($"{firstName}, {lastName}");// output: Nancy, Davolio
var (fName, lName, grade) = (Teacher)teacher;
Console.WriteLine($"{fName}, {lName}, {grade}");// output: Nancy, Davolio, 3
}
Algemene beperkingen
Het record
trefwoord is een wijzigingsfunctie voor een class
of struct
type. Het toevoegen van de record
wijzigingsfunctie bevat het gedrag dat eerder in dit artikel is beschreven. Er is geen algemene beperking waarvoor een type een record moet zijn. Een record class
voldoet aan de class
beperking. Een record struct
voldoet aan de struct
beperking. Zie Beperkingen voor typeparameters voor meer informatie.
C#-taalspecificatie
Zie de sectie Klassen van de C#-taalspecificatie voor meer informatie.
Zie de volgende opmerkingen over functievoorstel voor meer informatie over deze functies: