Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
record Modifikátor poskytuje integrované funkce pro zapouzdření dat.
record class A record syntaxe definují odkazové typy. Syntaxe record struct definuje typ hodnoty.
Referenční dokumentace jazyka C# dokumentuje naposledy vydané verze jazyka C#. Obsahuje také počáteční dokumentaci k funkcím ve verzi Public Preview pro nadcházející jazykovou verzi.
Dokumentace identifikuje všechny funkce, které byly poprvé představeny v posledních třech verzích jazyka nebo v aktuálních verzích Public Preview.
Návod
Informace o tom, kdy byla funkce poprvé představena v jazyce C#, najdete v článku o historii verzí jazyka C#.
Když deklarujete primární konstruktor v záznamu, kompilátor generuje veřejné vlastnosti pro parametry primárního konstruktoru. Parametry primárního konstruktoru záznamu jsou poziční parametry. Kompilátor vytvoří poziční vlastnosti , které zrcadlí primární konstruktor nebo poziční parametry. Kompilátor syntetizuje vlastnosti pro primární parametry konstruktoru record u typů, které nemají modifikátor.
Následující dva příklady ukazují record (nebo record class) odkazové typy:
public record Person(string FirstName, string LastName);
public record Person
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
};
Následující dva příklady ukazují record struct typy hodnot:
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; }
}
Můžete také vytvořit záznamy s proměnlivými vlastnostmi a poli:
public record Person
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
};
Struktury záznamů můžou být také proměnlivé, a to jak struktury pozičních záznamů, tak struktury záznamů bez pozičních parametrů:
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; }
}
Záznamy sice můžou být proměnlivé, ale primárně slouží k podpoře neměnných datových modelů. Typ záznamu nabízí následující funkce:
- Stručná syntaxe pro vytvoření referenčního typu s neměnnými vlastnostmi
- Předdefinované chování užitečné pro referenční typ orientovaný na data:
- Podpora hierarchií dědičnosti
Předchozí příklady ukazují několik rozdílů mezi záznamy, které jsou odkazovými typy a záznamy, které jsou typy hodnot:
- A
recordnebo deklarujerecord classtyp odkazu. Klíčovéclassslovo je volitelné, ale může pro čtenáře přidat přehlednost. Arecord structdeklaruje typ hodnoty. - Poziční vlastnosti jsou neměnné v objektu a .
record classreadonly record structJsou proměnlivé v objekturecord struct.
Zbývající část tohoto článku popisuje oba record class typy i record struct typy. Rozdíly jsou podrobně popsané v jednotlivých částech. Rozhodněte se mezi a record classrecord struct podobným rozhodnutím mezi a classstruct. Záznam termínu popisuje chování, které platí pro všechny typy záznamů. Buď record struct nebo record class slouží k popisu chování, které se vztahuje pouze na struktury nebo typy tříd v uvedeném pořadí.
Poziční syntaxe pro definici vlastnosti a pole
Pomocí pozičních parametrů můžete deklarovat vlastnosti záznamu nebo inicializovat hodnoty vlastností nebo polí. Následující příklad vytvoří záznam se dvěma pozičními vlastnostmi:
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 }
}
Pokud použijete poziční syntaxi pro definici vlastnosti, kompilátor vytvoří:
- Veřejná vlastnost automaticky implementovaná pro každý poziční parametr zadaný v deklaraci záznamu.
- Pro
recordtypy areadonly record structtypy: Vlastnost pouze inicializační. - Pro
record structtypy: Vlastnost pro čtení i zápis.
- Pro
- Primární konstruktor, jehož parametry odpovídají pozičním parametrům deklarace záznamu.
- U typů struktury záznamů je konstruktor bez parametrů, který nastaví každé pole na výchozí hodnotu.
- Metoda
Deconstructs parametremoutpro každý poziční parametr zadaný v deklaraci záznamu. Metoda dekonstruuje vlastnosti definované pomocí poziční syntaxe; ignoruje vlastnosti definované pomocí standardní syntaxe vlastností.
Do některého z těchto prvků můžete přidat atributy, které kompilátor vytvoří z definice záznamu. Cíl můžete přidat do libovolného atributu, který použijete u vlastností pozičního záznamu. Následující příklad platí pro System.Text.Json.Serialization.JsonPropertyNameAttribute každou vlastnost záznamu Person . Cíl property: označuje, že atribut se použije na vlastnost vygenerovanou kompilátorem. Další hodnoty mají field: použít atribut na pole a param: použít atribut na parametr.
/// <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);
Předchozí příklad také ukazuje, jak vytvořit komentáře dokumentace XML pro záznam. Značku můžete přidat a přidat <param> dokumentaci k parametrům primárního konstruktoru.
Pokud vygenerovaná definice automaticky implementované vlastnosti není to, co chcete, definujte vlastní vlastnost nebo pole se stejným názvem. Můžete například chtít změnit přístupnost nebo mutovatelnost nebo poskytnout implementaci get nebo set přístupového objektu. Pokud deklarujete člena ve zdroji, musíte ho inicializovat z pozičního parametru záznamu. Pokud je vaše vlastnost automaticky implementovaná, musíte vlastnost inicializovat. Pokud do zdroje přidáte záložní pole, musíte inicializovat backingové pole. Vygenerovaný dekonstruktor používá vaši vlastnost nebo definici pole. Například následující příklad deklaruje FirstName a LastName vlastnosti pozičního záznamu public, ale omezuje Id poziční parametr na internal. Tuto syntaxi můžete použít pro záznamy a typy struktury záznamů.
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
}
Pokud chcete vytvořit pole místo vlastnosti, přiřaďte poziční parametr k poli, jak je znázorněno v následujícím příkladu:
public record Person(string FirstName, string LastName, string Id)
{
internal readonly string Id = Id; // this.Id set to parameter Id
}
public static void Main()
{
Person person = new("Nancy", "Davolio", "12345");
Console.WriteLine(person.FirstName); //output: Nancy
}
Typ záznamu nemusí deklarovat žádné poziční vlastnosti. Můžete deklarovat záznam bez jakýchkoli pozičních vlastností a můžete deklarovat další pole a vlastnosti, jako v následujícím příkladu:
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; } = [];
};
Vlastnosti, které kompilátor generuje z pozičních parametrů, jsou public. Modifikátory přístupu deklarujete u všech vlastností, které explicitně deklarujete.
Neměnitelnost
Třída poziční záznam a poziční pouze pro čtení struktura záznamu deklarují vlastnosti pouze pro inicializaci. Struktura pozičního záznamu deklaruje vlastnosti pro čtení i zápis. Můžete přepsat kteroukoli z těchto výchozích hodnot, jak je znázorněno v předchozí části.
Neměnnost může být užitečná v případě, že potřebujete typ orientovaný na data, který je bezpečný pro vlákno, nebo když závisíte na kódu hash, který zůstane stejný v tabulce hash. Neměnnost ale není vhodná pro všechny scénáře dat. Entity Framework Core například nepodporuje aktualizaci pomocí neměnných typů entit.
Inicializační vlastnosti, ať už vytvořené z pozičních parametrů (record class a readonly record struct) nebo určením init přístupových objektů, mají neměnnost. Po inicializaci nelze změnit hodnotu vlastností typu hodnoty ani odkaz na vlastnosti typu odkazu. Data, na která odkazuje vlastnost typu odkaz, je však možné změnit. Následující příklad ukazuje, že obsah neměnné vlastnosti typu odkazu (v tomto případě pole) je proměnlivý:
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
}
Funkce, které jsou jedinečné pro typy záznamů, jsou implementovány syntetizovanými metodami kompilátoru a žádná z těchto metod nezhroužuje neměnnost úpravou stavu objektu. Pokud není uvedeno, syntetizované metody jsou generovány pro record, record structa readonly record struct deklarace.
Rovnost hodnot
Pokud nepřepíšete nebo nenahrazujete metody rovnosti, typ, který deklarujete, určuje, jak je definována rovnost:
- Pro
classtypy jsou dva objekty stejné, pokud odkazují na stejný objekt v paměti. - Pro
structtypy jsou dva objekty stejné, pokud jsou stejného typu a ukládají stejné hodnoty. - U typů s modifikátorem
record(record class,record structareadonly record struct) jsou dva objekty stejné, pokud jsou stejného typu a ukládají stejné hodnoty.
Definice rovnosti pro a record struct je stejná jako u .struct Rozdíl je v tom, že implementace structje v ValueType.Equals(Object) a spoléhá na reflexi. U záznamů je implementace syntetizována kompilátorem a používá deklarované datové členy.
U některých datových modelů je vyžadována rovnost odkazů. Například Entity Framework Core závisí na rovnosti odkazů, aby se zajistilo, že pro to, co je koncepčně jedna entita, používá pouze jednu instanci typu entity. Z tohoto důvodu nejsou záznamy a struktury záznamů vhodné pro použití jako typy entit v Entity Framework Core.
Následující příklad znázorňuje rovnost hodnot typů záznamů:
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
}
K implementaci rovnosti hodnot kompilátor syntetizuje několik metod, včetně:
Přepsání .Object.Equals(Object) Pokud deklarujete přepsání explicitně, jedná se o chybu.
Tato metoda se používá jako základ pro statickou metodu Object.Equals(Object, Object) , pokud oba parametry nemají hodnotu null.
A
virtual, nebosealed,Equals(R? other)kdeRje typ záznamu. Tato metoda implementuje IEquatable<T>. Tuto metodu můžete deklarovat explicitně.Je-li typ záznamu odvozen od základního typu
Basezáznamu ,Equals(Base? other). Pokud deklarujete přepsání explicitně, jedná se o chybu. Pokud zadáte vlastní implementaciEquals(R? other), uveďte také implementaciGetHashCode.Přepsání .Object.GetHashCode() Tuto metodu můžete deklarovat explicitně.
Přepsání operátoru
==a operátoru!=. Pokud explicitně deklarujete operátory, jedná se o chybu.Pokud je typ záznamu odvozen od základního typu záznamu,
protected override Type EqualityContract { get; };. Tuto vlastnost můžete deklarovat explicitně. Další informace naleznete v tématu Rovnost v hierarchiích dědičnosti.
Kompilátor syntetizuje metodu, pokud typ záznamu má metodu, která odpovídá podpisu syntetizované metody a metoda může být deklarována explicitně.
Nedestruktivní mutaci
Pokud potřebujete zkopírovat instanci s některými úpravami, použijte with výraz k dosažení nedestruktivní mutaci. Výraz with vytvoří novou instanci záznamu, která je kopií existující instance záznamu, ale se zadanými vlastnostmi a poli změněnými. Pomocí syntaxe inicializátoru objektů určete hodnoty, které se mají změnit, jak je znázorněno v následujícím příkladu:
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
}
Výraz with může nastavit poziční vlastnosti nebo vlastnosti vytvořené pomocí standardní syntaxe vlastností. Explicitně deklarované vlastnosti musí mít ve výrazu init změněný set objekt nebo with přístup.
Výsledkem výrazu with je mělká kopie. Pro vlastnost odkazu výraz zkopíruje pouze odkaz na instanci. Původní záznam i kopie končí odkazem na stejnou instanci.
K implementaci této funkce pro record class typy kompilátor syntetizuje klonovací metodu a konstruktor kopírování. Metoda virtuálního klonu vrátí nový záznam inicializovaný konstruktorem kopírování. Při použití výrazu with kompilátor vytvoří kód, který volá metodu klonu a potom nastaví vlastnosti, které with výraz obsahuje.
Důležité
Kompilátor také syntetizuje veřejný konstruktor bez parametrů, pokud záznam neobsahuje primární konstruktor nebo jakékoli uživatelem definované konstruktory. Tento konstruktor bez parametrů inicializuje všechna pole na výchozí hodnoty. Bez tohoto syntetizovaného konstruktoru není k dispozici žádný veřejný konstruktor.
Pokud potřebujete jiné chování kopírování, napište vlastní konstruktor kopírování do .record class Pokud to uděláte, kompilátor ho syntetizuje. Vytvořte konstruktor private , pokud je sealedzáznam . Jinak to protectedudělejte . Kompilátor syntetizuje konstruktor kopírování pro record struct typy. Můžete ho napsat, ale kompilátor negeneruje volání pro with výrazy. Hodnoty se record struct zkopírují při přiřazení.
Klonovací metodu nemůžete přepsat a nemůžete vytvořit člena pojmenovaného Clone v žádném typu záznamu. Skutečný název klonovací metody je vygenerován kompilátorem.
Důležité
V předchozích příkladech jsou všechny vlastnosti nezávislé. Žádná z vlastností se nevypočítá z jiných hodnot vlastností. Výraz with nejprve zkopíruje existující instanci záznamu a potom upraví všechny vlastnosti nebo pole, která with výraz obsahuje. Vypočítané vlastnosti v record typech by se měly vypočítat při přístupu, ne inicializovat při vytvoření instance. V opačném případě by vlastnost mohla vrátit vypočítanou hodnotu na základě původní instance, nikoli upravené kopie.
Správnost vypočítaných vlastností zajistíte tak, že vypočítáte hodnotu pro přístup, jak je znázorněno v následující deklaraci:
public record Point(int X, int Y)
{
public double Distance => Math.Sqrt(X * X + Y * Y);
}
Předchozí typ záznamu Distance vypočítá při přístupu, jak je znázorněno v následujícím příkladu:
Point p1 = new Point(3, 4);
Console.WriteLine($"Original point: {p1}");
p1 = p1 with { Y = 8 };
Console.WriteLine($"Modified point: {p1}");
// Output:
// Original point: Point { X = 3, Y = 4, Distance = 5 }
// Modified point: Point { X = 3, Y = 8, Distance = 8.54400374531753 }
Naopak tento přístup s následující deklarací, kde Distance se vlastnost vypočítá a ukládá do mezipaměti jako součást inicializace nové instance:
public record PointInit(int X, int Y)
{
public double Distance { get; } = Math.Sqrt(X * X + Y * Y);
}
Vzhledem k tomu Distance , že se vypočítá jako součást inicializace, hodnota se vypočítá a ukládá do mezipaměti před with tím, než výraz změní hodnotu Y v kopii. Výsledkem je nesprávná vzdálenost:
PointInit pt1 = new PointInit(3, 4);
Console.WriteLine($"Original point: {pt1}");
pt1 = pt1 with { Y = 8 };
Console.WriteLine($"Incorrect Modified point: {pt1}");
// Output:
// Original point: PointInit { X = 3, Y = 4, Distance = 5 }
// Modified point: PointInit { X = 3, Y = 8, Distance = 5 }
Výpočet Distance není nákladný pro výpočet jednotlivých přístupů. Některé vypočítané vlastnosti ale můžou vyžadovat přístup k více datům nebo rozsáhlejšímu výpočtu. V takových případech místo záznamu použijte class typ a vypočítat hodnotu uloženou v mezipaměti, když jedna z komponent změní hodnotu.
Integrované formátování pro zobrazení
Typy záznamů mají metodu vygenerovanou ToString kompilátorem, která zobrazuje názvy a hodnoty veřejných vlastností a polí. Metoda ToString vrátí řetězec v následujícím formátu:
<název typu záznamu { >název<> vlastnosti = <hodnota>, <název> vlastnosti = <hodnota>, ...}
Řetězec vytištěný <value> pro je řetězec vrácený ToString() typem vlastnosti. V následujícím příkladu ChildNames je , System.Arraykde ToString vrátí System.String[]:
Person { FirstName = Nancy, LastName = Davolio, ChildNames = System.String[] }
K implementaci této funkce kompilátor v record class typech syntetizuje virtuální PrintMembers metodu a přepsání ToString . V record struct typech je privatetento člen .
Přepsání ToString vytvoří StringBuilder objekt s názvem typu následovaným levou závorkou.
PrintMembers Volá přidání názvů a hodnot vlastností a pak přidá pravou hranaté závorku. Následující příklad ukazuje kód podobný syntetizovanému přepsání obsahuje:
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();
}
Můžete zadat vlastní implementaci PrintMembers nebo přepsání ToString . Příklady jsou uvedeny ve formátování v oddílu PrintMembers odvozených záznamů dále v tomto článku. Vaše implementace ToString může zahrnovat modifikátor sealed, který brání kompilátoru v syntetizaci implementace ToString pro všechny odvozené záznamy. Můžete vytvořit konzistentní řetězcovou reprezentaci v celé hierarchii record typů. (Odvozené záznamy mají stále vygenerovanou metodu PrintMembers pro všechny odvozené vlastnosti.)
Dědičnost
Tato část se vztahuje pouze na record class typy.
Záznam může dědit z jiného záznamu. Záznam však nemůže dědit z třídy a třída nemůže dědit ze záznamu.
Poziční parametry v odvozených typech záznamů
Odvozený záznam deklaruje poziční parametry pro všechny parametry v primárním konstruktoru základního záznamu. Základní záznam deklaruje a inicializuje tyto vlastnosti. Odvozený záznam je neskryje, ale vytvoří a inicializuje vlastnosti parametrů, které nejsou deklarovány v základním záznamu.
Následující příklad znázorňuje dědičnost se syntaxí poziční vlastnosti:
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 }
}
Rovnost v hierarchiích dědičnosti
Tato část se týká record class typů, ale ne record struct typů. Aby byly dvě proměnné záznamů stejné, musí být typ běhu roven. Typy obsahujících proměnných se můžou lišit. Porovnání zděděné rovnosti je znázorněno v následujícím příkladu kódu:
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
}
V příkladu jsou všechny proměnné deklarovány jako Person, i když je instance odvozený typ buď Student nebo Teacher. Instance mají stejné vlastnosti a stejné hodnoty vlastností. I student == teacher když jsou Falseobě proměnné typu -type, a Person vracístudent == student2, i když jedna je proměnná True a jedna je proměnnáPerson.Student Test rovnosti závisí na typu modulu runtime skutečného objektu, nikoli deklarovaného typu proměnné.
K implementaci tohoto chování kompilátor syntetizuje EqualityContract vlastnost, která vrací Type objekt, který odpovídá typu záznamu. Umožňuje EqualityContract metodám rovnosti porovnat typ modulu runtime objektů při kontrole rovnosti. Pokud je objectzákladním typem záznamu , tato vlastnost je virtual. Pokud je základním typem jiný typ záznamu, je tato vlastnost přepsána. Pokud je sealedtyp záznamu , tato vlastnost je efektivní sealed , protože typ je sealed.
Když kód porovná dvě instance odvozeného typu, syntetizované metody rovnosti zkontrolují všechny datové členy základního a odvozeného typu rovnosti. Syntetizovaná GetHashCode metoda používá metodu GetHashCode ze všech datových členů deklarovaných v základním typu a odvozeného typu záznamu. Datové členy record zahrnutí všech deklarovaných polí a pole syntetizovaného kompilátoru pro všechny automaticky implementované vlastnosti.
with výrazy v odvozených záznamech
Výsledek výrazu with má stejný typ za běhu jako operand výrazu. Zkopírují se všechny vlastnosti typu runtime, ale můžete nastavit pouze vlastnosti typu kompilace, jak ukazuje následující příklad:
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 formátování v odvozených záznamech
Syntetizovaná PrintMembers metoda odvozeného typu záznamu volá základní implementaci. Výsledkem je, že do výstupu ToString jsou zahrnuty všechny veřejné vlastnosti a pole odvozených i základních typů, jak je znázorněno v následujícím příkladu:
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 }
}
Můžete zadat vlastní implementaci PrintMembers metody. Pokud to uděláte, použijte následující podpis:
- Pro záznam odvozený ze záznamu
sealed(deklaruje základní záznam):object;private bool PrintMembers(StringBuilder builder) -
sealedPro záznam, který je odvozen z jiného záznamu (všimněte si, že uzavřený typ jesealed, takže metoda je efektivnísealed):protected override bool PrintMembers(StringBuilder builder); - Pro záznam, který není
sealeda odvozuje z objektu:protected virtual bool PrintMembers(StringBuilder builder); - Pro záznam, který není
sealeda odvozen z jiného záznamu:protected override bool PrintMembers(StringBuilder builder);
Tady je příklad kódu, který nahrazuje syntetizované PrintMembers metody, jeden pro typ záznamu odvozený z objektu a jeden pro typ záznamu, který je odvozen od jiného záznamu:
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 }
}
Poznámka:
Kompilátor generuje PrintMembers v odvozených záznamech, i když základní záznam zapečetil metodu ToString. Můžete také vytvořit vlastní implementaci PrintMembers.
Chování dekonstruktoru v odvozených záznamech
Metoda Deconstruct odvozeného záznamu vrátí hodnoty všech pozičních vlastností typu kompilace. Pokud je typ proměnné základním záznamem, vrátí operace dekonstrukce pouze vlastnosti základního záznamu, pokud objekt není přetypován na odvozený typ. Následující příklad ukazuje volání dekonstruktor na odvozený záznam.
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
}
Obecná omezení
Klíčové record slovo je modifikátor pro typ class nebo typ struct . Přidání modifikátoru record zahrnuje chování popsané výše v tomto článku. Neexistuje žádné obecné omezení, které vyžaduje, aby typ byl záznamem. A record class splňuje class omezení. A record struct splňuje struct omezení. Další informace naleznete v tématu Omezení parametrů typu.
specifikace jazyka C#
Další informace najdete v části Třídy specifikace jazyka C#.
Další informace o těchto funkcích najdete v následujících poznámkách k návrhu funkcí: