Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Recordtyper är typer som använder värdebaserad jämställdhet. Du kan definiera poster som referenstyper eller värdetyper. Två variabler av en posttyp är lika med om posttypdefinitionerna är identiska, och om värdena i båda posterna för varje fält är lika. Två variabler av en klasstyp är lika om de objekt som avses är samma klasstyp och variablerna refererar till samma objekt. Värdebaserad likhet innebär andra funktioner som du förmodligen vill ha i posttyper. Kompilatorn genererar många av dessa medlemmar när du deklarerar en record
i stället för en class
. Kompilatorn genererar samma metoder för record struct
typer.
I den här handledningen kommer du lära dig att:
- Bestäm om du ska lägga till
record
-modifieraren till enclass
-typ. - Deklarera posttyper och positionella posttyper.
- Ersätt dina metoder med kompilatorgenererade metoder i poster.
Förutsättningar
- Den senaste versionen av .NET SDK
- Visual Studio Code-redigerare
- C# DevKit
Egenskaper för poster
Du definierar en post genom att deklarera en typ med nyckelordet record
, ändra en class
eller struct
deklaration. Du kan också utelämna nyckelordet class
för att skapa en record class
. En post följer värdebaserad likhetssemantik. För att framtvinga värdesemantik genererar kompilatorn flera metoder för posttypen (både för record class
typer och record struct
typer):
- En åsidosättning av Object.Equals(Object).
- En virtuell
Equals
metod vars parameter är posttypen. - En åsidosättning av Object.GetHashCode().
- Metoder för
operator ==
ochoperator !=
. - Posttyper implementerar System.IEquatable<T>.
Register ger också en åsidosättning av Object.ToString(). Kompilatorn syntetiserar metoder för att visa poster med hjälp av Object.ToString(). Du utforskar dessa element när du skriver koden för den här handledningen. Poster stöder with
uttryck för att aktivera icke-förstörande mutation av poster.
Du kan också deklarera positional records med en mer koncis syntax. Kompilatorn syntetiserar fler metoder åt dig när du deklarerar positionella poster:
- En primär konstruktor vars parametrar matchar positionsparametrarna i rekorddeklarationen.
- Publika egenskaper för varje parameter i en primär konstruktor. Dessa egenskaper är init-only för
record class
typer ochreadonly record struct
typer. Förrecord struct
typer är de skrivskyddade. -
Deconstruct
metod för att extrahera egenskaper från dataposten.
Skapa temperaturdata
Data och statistik är några av de scenarier där du vill använda dataposter. I den här självstudien skapar du ett program som beräknar examensdagar för olika användningsområden. Graddagar är ett mått på värme (eller brist på värme) under en period av dagar, veckor eller månader. Examensdagar spårar och förutsäger energianvändning. Fler varmare dagar innebär mer luftkonditionering, och kallare dagar innebär mer ugnsanvändning. Graddagar hjälper till att hantera växtpopulationer och har samband med växttillväxten när årstiderna förändras. Graddagar hjälper till att spåra djurvandringar för arter som flyttar för att anpassa sig till klimatet.
Formeln baseras på medeltemperaturen på en viss dag och en baslinjetemperatur. För att beräkna graddagar över tid behöver du den höga och låga temperaturen varje dag under en tidsperiod. Vi börjar med att skapa ett nytt program. Skapa ett nytt konsolprogram. Skapa en ny posttyp i en ny fil med namnet "DailyTemperature.cs":
public readonly record struct DailyTemperature(double HighTemp, double LowTemp);
Föregående kod definierar en positional record. Posten DailyTemperature
är en readonly record struct
, eftersom du inte tänker ärva från den, och den bör vara oföränderlig.
HighTemp
Egenskaperna och LowTemp
är endast init-egenskaper, vilket innebär att de kan anges i konstruktorn eller med hjälp av en egenskapsinitierare. Om du vill att positionsparametrarna ska vara läs- och skrivbara, deklarerar du en record struct
i stället för en readonly record struct
. Typen DailyTemperature
har också en primär konstruktor som har två parametrar som matchar de två egenskaperna. Du använder den primära konstruktorn för att initiera en DailyTemperature
post. Följande kod skapar och initierar flera DailyTemperature
rekord. Den första använder namngivna parametrar för att klargöra HighTemp
och LowTemp
. De återstående initierarna använder positionsparametrar för att initiera HighTemp
och LowTemp
:
private static DailyTemperature[] data = [
new DailyTemperature(HighTemp: 57, LowTemp: 30),
new DailyTemperature(60, 35),
new DailyTemperature(63, 33),
new DailyTemperature(68, 29),
new DailyTemperature(72, 47),
new DailyTemperature(75, 55),
new DailyTemperature(77, 55),
new DailyTemperature(72, 58),
new DailyTemperature(70, 47),
new DailyTemperature(77, 59),
new DailyTemperature(85, 65),
new DailyTemperature(87, 65),
new DailyTemperature(85, 72),
new DailyTemperature(83, 68),
new DailyTemperature(77, 65),
new DailyTemperature(72, 58),
new DailyTemperature(77, 55),
new DailyTemperature(76, 53),
new DailyTemperature(80, 60),
new DailyTemperature(85, 66)
];
Du kan lägga till egna egenskaper eller metoder i poster, inklusive positionella poster. Du måste beräkna medeltemperaturen för varje dag. Du kan lägga till den egenskapen till posten DailyTemperature
.
public readonly record struct DailyTemperature(double HighTemp, double LowTemp)
{
public double Mean => (HighTemp + LowTemp) / 2.0;
}
Nu ska vi se till att du kan använda dessa data. Lägg till följande kod i din Main
metod:
foreach (var item in data)
Console.WriteLine(item);
Kör programmet och du ser utdata som liknar följande visning (flera rader har tagits bort för utrymme):
DailyTemperature { HighTemp = 57, LowTemp = 30, Mean = 43.5 }
DailyTemperature { HighTemp = 60, LowTemp = 35, Mean = 47.5 }
DailyTemperature { HighTemp = 80, LowTemp = 60, Mean = 70 }
DailyTemperature { HighTemp = 85, LowTemp = 66, Mean = 75.5 }
Föregående kod visar utdata från åsidosättningen av ToString
syntetiserad av kompilatorn. Om du föredrar annan text kan du skriva en egen version av ToString
den som förhindrar att kompilatorn syntetiserar en version åt dig.
Beräkna graddagar
För att beräkna gradersdagar tar du skillnaden från en baslinjetemperatur och medeltemperaturen en viss dag. Om du vill mäta värme över tid tar du bort alla dagar där medeltemperaturen ligger under baslinjen. Om du vill mäta kyla över tid tar du bort alla dagar där medeltemperaturen ligger över baslinjen. Usa använder till exempel 65 F som bas för både uppvärmnings- och kylningsgrader. Det är temperaturen där ingen uppvärmning eller kylning behövs. Om en dag har en medeltemperatur på 70 F, motsvarar den dagen fem kylgrad dagar och noll värmegrad dagar. Å andra sidan, om medeltemperaturen är 55 F, är den dagen 10 värmegraderdagar och 0 kylgraderdagar.
Du kan uttrycka dessa formler som en liten hierarki med posttyper: en abstrakt typ av grad-dag och två konkreta typer för uppvärmningsgrad-dagar och kylgrad-dagar. Dessa typer kan också vara positionsposter. De tar en baslinjetemperatur och en sekvens med dagliga temperaturmätningar som argument till primärkonstruktorn:
public abstract record DegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords);
public sealed record HeatingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean < BaseTemperature).Sum(s => BaseTemperature - s.Mean);
}
public sealed record CoolingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean > BaseTemperature).Sum(s => s.Mean - BaseTemperature);
}
Den abstrakta DegreeDays
posten är den delade basklassen för både HeatingDegreeDays
- och CoolingDegreeDays
-post. De primära konstruktordeklarationerna på de härledda posterna visar hur du hanterar initiering av basposter. Din härledda post deklarerar parametrar för alla parametrar i baspostens primärkonstruktor. Basrecordet deklarerar och initierar de egenskaperna. Den härledda posten döljer dem inte, utan skapar och initierar bara egenskaper för parametrar som inte deklareras i basposten. I det här exemplet lägger de härledda posterna inte till nya primära konstruktorparametrar. Testa koden genom att lägga till följande kod i din Main
metod:
var heatingDegreeDays = new HeatingDegreeDays(65, data);
Console.WriteLine(heatingDegreeDays);
var coolingDegreeDays = new CoolingDegreeDays(65, data);
Console.WriteLine(coolingDegreeDays);
Du får utdata som liknar följande:
HeatingDegreeDays { BaseTemperature = 65, TempRecords = record_types.DailyTemperature[], DegreeDays = 85 }
CoolingDegreeDays { BaseTemperature = 65, TempRecords = record_types.DailyTemperature[], DegreeDays = 71.5 }
Definiera kompilatorsyntetiserade metoder
Koden beräknar rätt antal dagar för uppvärmning och kylning under den tidsperioden. Men det här exemplet visar varför du kanske vill ersätta några av de syntetiserade metoderna för poster. Du kan deklarera din egen version av någon av de kompilatorsyntetiserade metoderna i en posttyp förutom klonmetoden. Klonmetoden har ett kompilatorgenererat namn och du kan inte ange någon annan implementering. Dessa syntetiserade metoder omfattar en kopieringskonstruktor, medlemmarna System.IEquatable<T> i gränssnittet, likhets- och ojämlikhetstester och GetHashCode(). För det här ändamålet syntetiserar du PrintMembers
. Du kan också deklarera dina egna ToString
, men PrintMembers
ger ett bättre alternativ för arvsscenarier. Om du vill ange din egen version av en syntetiserad metod måste signaturen matcha den syntetiserade metoden.
Elementet TempRecords
i konsolens utdata är inte användbart. Den visar typen, men inget annat. Du kan ändra det här beteendet genom att tillhandahålla en egen implementering av den syntetiserade PrintMembers
metoden. Signaturen är beroende av modifierare som tillämpas på deklarationen record
:
- Om en posttyp är
sealed
, eller enrecord struct
, är signaturenprivate bool PrintMembers(StringBuilder builder);
- Om en posttyp inte är
sealed
och härleds frånobject
(det vill säga att den inte deklarerar en basposttyp), är signaturenprotected virtual bool PrintMembers(StringBuilder builder);
- Om en posttyp inte är
sealed
och härleds från en annan posttyp, är signaturenprotected override bool PrintMembers(StringBuilder builder);
De här reglerna är enklast att förstå genom att förstå syftet med PrintMembers
.
PrintMembers
lägger till information om varje egenskap i en posttyp i en sträng. Kontraktet kräver att basdata lägger till sina medlemmar på skärmen och förutsätter att härledda medlemmar lägger till sina medlemmar. Varje posttyp syntetiserar en ToString
överskrivning som liknar följande exempel för HeatingDegreeDays
:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("HeatingDegreeDays");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}
Du deklarerar en PrintMembers
metod i en DegreeDays
record som inte skriver ut typ av samling.
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"BaseTemperature = {BaseTemperature}");
return true;
}
Signaturen deklarerar en virtual protected
metod som matchar kompilatorns version. Oroa dig inte om du får åtkomsterna fel; språket framtvingar rätt signatur. Om du glömmer rätt modifierare för någon syntetiserad metod utfärdar kompilatorn varningar eller fel som hjälper dig att få rätt signatur.
Du kan deklarera metoden ToString
som sealed
i en recordstruktur. Det förhindrar att härledda poster tillhandahåller en ny implementering. Härledda poster kommer fortfarande att innehålla åsidosättningen PrintMembers
. Du skulle försegla ToString
om du inte ville att den ska visa postens körtidstyp. I föregående exempel skulle du förlora informationen om var posten mätte uppvärmnings- eller kylningsgradsdagar.
Icke-förstörande mutation
De syntetiserade medlemmarna i en positionell postklass ändrar inte postens tillstånd. Målet är att du kan lättare skapa oföränderliga poster. Kom ihåg att du deklarerar ett readonly record struct
för att skapa en oföränderlig record-struct. Titta igen på föregående deklarationer för HeatingDegreeDays
och CoolingDegreeDays
. De tillagda medlemmarna utför beräkningar på värdena för posten, men ändrar inte tillståndet. Positionsposter gör det enklare för dig att skapa oföränderliga referenstyper.
Att skapa oföränderliga referenstyper innebär att du vill använda icke-förstörande mutation. Du skapar nya poster som liknar befintliga poster genom with
uttryck. Dessa uttryck utgör en konstruktion för kopiering med extra tilldelningar som modifierar kopian. Resultatet är en ny postinstans där varje egenskap kopierades från den befintliga posten och eventuellt ändrades. Den ursprungliga posten är oförändrad.
Nu ska vi lägga till några funktioner i ditt program som demonstrerar with
uttryck. Först ska vi skapa en ny post för att beräkna växande graddagar med samma data.
Växande graddagar använder vanligtvis 41 F som baslinje och mäter temperaturer över baslinjen. Om du vill använda samma data kan du skapa en ny post som liknar coolingDegreeDays
, men med en annan bastemperatur:
// Growing degree days measure warming to determine plant growing rates
var growingDegreeDays = coolingDegreeDays with { BaseTemperature = 41 };
Console.WriteLine(growingDegreeDays);
Du kan jämföra antalet grader som beräknas med de tal som genereras med en högre baslinjetemperatur. Kom ihåg att poster är referenstyper och att dessa kopior är ytliga kopior. Matrisen för data kopieras inte, men båda posterna refererar till samma data. Detta faktum är en fördel i ett annat scenario. För växande graddagar är det bra att hålla reda på summan för de senaste fem dagarna. Du kan skapa nya poster med olika källdata med hjälp av with
uttryck. Följande kod skapar en samling av dessa ackumuleringar och visar sedan värdena:
// showing moving accumulation of 5 days using range syntax
List<CoolingDegreeDays> movingAccumulation = new();
int rangeSize = (data.Length > 5) ? 5 : data.Length;
for (int start = 0; start < data.Length - rangeSize; start++)
{
var fiveDayTotal = growingDegreeDays with { TempRecords = data[start..(start + rangeSize)] };
movingAccumulation.Add(fiveDayTotal);
}
Console.WriteLine();
Console.WriteLine("Total degree days in the last five days");
foreach(var item in movingAccumulation)
{
Console.WriteLine(item);
}
Du kan också använda with
-uttryck för att skapa kopior av poster. Ange inga egenskaper mellan klammerparenteserna för with
uttrycket. Det innebär att skapa en kopia och inte ändra några egenskaper:
var growingDegreeDaysCopy = growingDegreeDays with { };
Kör det färdiga programmet för att se resultatet.
Sammanfattning
Den här handledningen visade flera aspekter av journaler. Post ger en kortfattad syntax för typer där den grundläggande användningen är lagring av data. För objektorienterade klasser är den grundläggande användningen att definiera ansvarsområden. Den här självstudien fokuserar på positionella register, där du kan använda en koncis syntax för att deklarera egenskaperna hos ett register. Kompilatorn syntetiserar flera komponenter i posten för att kopiera och jämföra poster. Du kan lägga till andra medlemmar som du behöver för dina posttyper. Du kan skapa oföränderliga posttyper med vetskapen om att inte någon av de kompilatorskapade medlemmarna kommer att ändra tillståndet. Och with
uttryck gör det enkelt att stödja icke-förstörande mutation.
Rekord lägger till ett annat sätt att definiera typer. Du använder class
definitioner för att skapa objektorienterade hierarkier som fokuserar på objektens ansvarsområden och beteende. Du skapar struct
typer för datastrukturer som lagrar data och är tillräckligt små för att kopiera effektivt. Du skapar record
typer när du vill ha värdebaserad likhet och jämförelse, inte vill kopiera värden och vill använda referensvariabler. Du skapar record struct
typer när du vill ha funktionerna i poster för en typ som är tillräckligt liten för att kopiera effektivt.
Du kan lära dig mer om poster i C#-språkreferensartikeln för posttypen och den föreslagna posttypspecifikationen och poststruktureringsspecifikationen.