Share via


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:

In de voorgaande voorbeelden ziet u een aantal onderscheid tussen records die verwijzingstypen en records zijn die waardetypen zijn:

  • A record of a record class declareert een verwijzingstype. Het class trefwoord is optioneel, maar kan duidelijkheid voor lezers toevoegen. A record struct declareert een waardetype.
  • Positionele eigenschappen zijn onveranderbaar in een record class en een readonly record struct. Ze zijn veranderlijk in een record 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 en readonly record struct typen: een eigenschap die alleen init is.
    • Voor record struct typen: een eigenschap lezen/schrijven.
  • 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 een out 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 publicdeclareren, 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 classen 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 structen 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 structen readonly 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, of sealed, Equals(R? other) waar R 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 van Equals(R? other), geef dan ook een implementatie van GetHashCode .

  • 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 privatedit 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 StudentTeacher. De exemplaren hebben dezelfde eigenschappen en dezelfde eigenschapswaarden. Maar student == teacher retourneert False hoewel beide -type variabelen zijn Personen 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 objectvirtualdeze eigenschap . Als het basistype een ander recordtype is, is deze eigenschap een onderdrukking. Als het recordtype is, is sealeddeze 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 van object (declareert geen basisrecord): private bool PrintMembers(StringBuilder builder)
  • Voor een record die is afgeleid van een sealed andere record (let op: het insluittype is sealed, 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:

Zie ook