Nyheter i .NET 8
.NET 8 är efterföljare till .NET 7. Det kommer att stödjas i tre år som en långsiktig supportversion (LTS). Du kan ladda ned .NET 8 här.
Den här artikeln har uppdaterats för .NET 8 Preview 4.
Viktigt
- Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, avseende informationen som visas här.
- Mycket av den andra .NET-dokumentationen på https://learn.microsoft.com/dotnet har ännu inte uppdaterats för .NET 8.
Ändringar i .NET SDK
Det här avsnittet innehåller följande underavsnitt:
- Utdata från terminalbygge
- Förenklade utdatasökvägar
- Kommandot "dotnet workload clean" (rensa dotnet-arbetsbelastning)
- "dotnet publish" och "dotnet pack"-tillgångar
- Mallmotor
Utdata från terminalbygge
dotnet build
har ett nytt alternativ för att skapa mer moderniserade byggutdata. Den här terminalloggarens utdata grupperar fel med det projekt som de kom från, särskiljer bättre de olika målramverken för projekt med flera mål och ger realtidsinformation om vad bygget gör. Om du vill välja nya utdata använder du alternativet --tl
. Mer information om det här alternativet finns i dotnet-byggalternativ.
Förenklade utdatasökvägar
.NET 8 introducerar ett alternativ för att förenkla utdatasökvägen och mappstrukturen för byggutdata. Tidigare skapade .NET-appar en djup och komplex uppsättning utdatasökvägar för olika byggartefakter. Den nya förenklade utdatasökvägsstrukturen samlar alla byggutdata till en gemensam plats, vilket gör det enklare för verktyg att förutse.
Om du vill välja det nya sökvägsformatet för utdata använder du någon av följande egenskaper i filen Directory.Build.props :
- Lägg till en
ArtifactsPath
egenskap med värdet$(MSBuildThisFileDirectory)artifacts
(eller vad du vill att mappplatsen ska vara) ELLER - Om du vill använda standardplatsen anger du
UseArtifactsOutput
helt enkelt egenskapen tilltrue
.
Du kan också köra dotnet new buildprops --use-artifacts
och mallen genererar filen Directory.Build.props åt dig:
<Project>
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
</PropertyGroup>
</Project>
Som standard är den gemensamma platsen en mapp med namnet artifacts i lagringsplatsens rot i stället för i varje projektmapp. Mappstrukturen under mappen root artifacts är följande:
📁 artifacts
└──📂 <Type of output>
└──📂 <Project name>
└──📂 <Pivot>
I följande tabell visas standardvärdena för varje nivå i mappstrukturen. Värdena, samt standardplatsen, kan åsidosättas med hjälp av egenskaper i filen Directory.build.props .
Mappnivå | Description |
---|---|
Typ av utdata | Exempel: bin , obj , publish eller package |
Projektnamn | Separerar utdata efter varje projekt. |
Pivotera | Skiljer mellan byggen av ett projekt för olika konfigurationer, målramverk och körningsidentifierare. Om flera element behövs kopplas de med ett understreck (_ ). |
Kommandot dotnet workload clean
.NET 8 introducerar ett nytt kommando för att rensa arbetsbelastningspaket som kan lämnas över via flera .NET SDK- eller Visual Studio-uppdateringar. Om du stöter på problem när du hanterar arbetsbelastningar bör du överväga att använda workload clean
för att återställa till ett känt tillstånd innan du försöker igen. Kommandot har två lägen:
dotnet workload clean
Kör skräpinsamling för arbetsbelastningar för filbaserade eller MSI-baserade arbetsbelastningar, som rensar överblivna paket. Överblivna paket kommer från avinstallerade versioner av .NET SDK eller paket där installationsposterna för paketet inte längre finns.
Om Visual Studio är installerat visar kommandot även alla arbetsbelastningar som du bör rensa manuellt med Visual Studio.
dotnet workload clean --all
Det här läget är mer aggressivt och rensar varje paket på datorn som är av den aktuella SDK-arbetsbelastningsinstallationstypen (och det är inte från Visual Studio). Den tar också bort alla installationsposter för arbetsbelastningar för det .NET SDK-funktionsband som körs och nedan.
dotnet publish
och dotnet pack
tillgångar
Eftersom kommandona dotnet publish
och dotnet pack
är avsedda att producera produktionstillgångar producerar Release
de nu tillgångar som standard.
Följande utdata visar det olika beteendet mellan dotnet build
och och och hur du kan återgå till att publicera Debug
tillgångar genom att ange PublishRelease
egenskapen till false
dotnet publish
.
/app# dotnet new console
/app# dotnet build
app -> /app/bin/Debug/net8.0/app.dll
/app# dotnet publish
app -> /app/bin/Release/net8.0/app.dll
app -> /app/bin/Release/net8.0/publish/
/app# dotnet publish -p:PublishRelease=false
app -> /app/bin/Debug/net8.0/app.dll
app -> /app/bin/Debug/net8.0/publish/
Mer information finns i "dotnet pack" använder versionskonfiguration och "dotnet publish" använder versionskonfiguration.
dotnet restore
säkerhetsgranskning
Från och med .NET 8 kan du välja säkerhetskontroller för kända säkerhetsrisker när beroendepaket återställs. Den här granskningen skapar en rapport över säkerhetsrisker med det berörda paketnamnet, säkerhetsriskens allvarlighetsgrad och en länk till rekommendationen för mer information. När du kör dotnet add
eller dotnet restore
visas varningar för NU1901-NU1904 för eventuella säkerhetsrisker som hittas. Mer information finns i Granskning av säkerhetsrisker.
Mallmotor
Mallmotorn ger en säkrare upplevelse i .NET 8 genom att integrera några av NuGets säkerhetsrelaterade funktioner. Förbättringarna innefattar:
Förhindra att paket laddas ned från
http://
feeds som standard. Följande kommando kan till exempel inte installera mallpaketet eftersom käll-URL:en inte använder HTTPS.dotnet new install console --add-source "http://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json"
Du kan åsidosätta den här begränsningen
--force
med hjälp av flaggan .För
dotnet new
,dotnet new install
ochdotnet new update
kontrollerar du om det finns kända säkerhetsrisker i mallpaketet. Om säkerhetsrisker hittas och du vill fortsätta måste du använda--force
flaggan .För
dotnet new
anger du information om mallpaketets ägare. Ägarskapet verifieras av NuGet-portalen och kan betraktas som en pålitlig egenskap.För
dotnet search
ochdotnet uninstall
anger du om en mall har installerats från ett paket som är "betrott", dvs. det använder ett reserverat prefix.
Serialisering
Många förbättringar har gjorts för System.Text.Json serialiserings- och deserialiseringsfunktioner, bland annat:
- Prestanda- och tillförlitlighetsförbättringar för källgeneratorn när den används med ASP.NET Core i interna AOT-appar.
- Källgeneratorn stöder nu serialiseringstyper med
required
egenskaper ochinit
. Båda dessa stöds redan i reflektionsbaserad serialisering. - Du kan anpassa hanteringen av medlemmar som inte finns i JSON-nyttolasten.
- JsonSerializerOptions.MakeReadOnly() ger dig explicit kontroll över när en
JsonSerializerOptions
instans är låst. (Du kan också kontrollera det med IsReadOnly egenskapen .) - JsonSerializerOptions.AddContext<TContext>() är nu föråldrad. Det har ersatts av TypeInfoResolver egenskaperna och TypeInfoResolverChain . Mer information finns i Kedjekällgeneratorer.
- Den nya TryGetTypeInfo(Type, JsonTypeInfo) metoden, en variant av den befintliga GetTypeInfo(Type) metoden, returnerar
false
om inga metadata för den angivna typen hittades. - .NET 8 lägger till stöd för kompilatorgenererade eller obeskrattbara typer i svagt typifierade källgenereringsscenarier. Eftersom kompilatorgenererade typer inte uttryckligen kan anges av källgeneratorn utför System.Text.Json nu den närmast överordnade upplösningen vid körning. Den här upplösningen bestämmer den lämpligaste supertypen som värdet ska serialiseras med.
Följande avsnitt går in närmare på andra serialiseringsförbättringar:
- Gränssnittshierarkier
- Namngivningsprinciper
- Skrivskyddade egenskaper
- Inaktivera reflektionsbaserad standard
- Kedjekällgeneratorer
Mer information om JSON-serialisering i allmänhet finns i JSON-serialisering och deserialisering i .NET.
Gränssnittshierarkier
.NET 8 lägger till stöd för serialisering av egenskaper från gränssnittshierarkier.
Följande kod visar ett exempel där egenskaperna från både det omedelbart implementerade gränssnittet och dess basgränssnitt serialiseras.
IDerived value = new DerivedImplement { Base = 0, Derived = 1 };
JsonSerializer.Serialize(value); // {"Base":0,"Derived":1}
public interface IBase
{
public int Base { get; set; }
}
public interface IDerived : IBase
{
public int Derived { get; set; }
}
public class DerivedImplement : IDerived
{
public int Base { get; set; }
public int Derived { get; set; }
}
Namngivningsprinciper
JsonNamingPolicy
innehåller nya namngivningsprinciper för snake_case
(med understreck) och kebab-case
(med bindestreck) egenskapsnamnkonverteringar. Använd dessa principer på samma sätt som den befintliga JsonNamingPolicy.CamelCase principen:
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" }
Skrivskyddade egenskaper
Nu kan du deserialisera till skrivskyddade fält eller egenskaper (det vill: de som inte har någon set
accessor).
Om du vill välja det här stödet globalt anger du ett nytt alternativ, PreferredObjectCreationHandling, till JsonObjectCreationHandling.Populate. Om kompatibilitet är ett problem kan du också aktivera funktionen mer detaljerat genom att placera [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
attributet på typer vars egenskaper ska fyllas i eller på enskilda egenskaper.
Tänk dig till exempel följande kod som deserialiserar till en CustomerInfo
typ som har två skrivskyddade egenskaper.
using System.Text.Json;
CustomerInfo customer =
JsonSerializer.Deserialize<CustomerInfo>("""{"Name":"John Doe","Company":{"Name":"Contoso"}}""")!;
Console.WriteLine(JsonSerializer.Serialize(customer));
class CompanyInfo
{
public required string Name { get; set; }
public string? PhoneNumber { get; set; }
}
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class CustomerInfo
{
// Both of these properties are read-only.
public string Name { get; } = "Anonymous";
public CompanyInfo Company { get; } = new() { Name = "N/A", PhoneNumber = "N/A" };
}
Före .NET 8 ignorerades indatavärdena och Name
egenskaperna och Company
behöll sina standardvärden.
{"Name":"Anonymous","Company":{"Name":"N/A","PhoneNumber":"N/A"}}
Nu används indatavärdena för att fylla i de skrivskyddade egenskaperna under deserialiseringen.
{"Name":"John Doe","Company":{"Name":"Contoso","PhoneNumber":null}}
Inaktivera reflektionsbaserad standard
Du kan nu inaktivera med hjälp av den reflektionsbaserade serialiseraren som standard. Den här inaktiveringen är användbar för att undvika oavsiktlig rotning av reflektionskomponenter som inte ens används, särskilt i trimmade och inbyggda AOT-appar. Om du vill inaktivera standardreflektionsbaserad serialisering genom att kräva att ett JsonSerializerOptions argument skickas till JsonSerializer serialiserings- och deserialiseringsmetoderna JsonSerializer.IsReflectionEnabledByDefault
anger du egenskapen till false
i projektfilen. (Om egenskapen är inställd på false
och du inte skickar ett konfigurerat JsonSerializerOptions argument Serialize
genererar metoderna och Deserialize
en NotSupportedException vid körning.)
Använd den nya IsReflectionEnabledByDefault egenskapen för att kontrollera värdet för funktionsväxeln. Om du är en biblioteksförfattare som bygger ovanpå System.Text.Jsonkan du förlita dig på egenskapen för att konfigurera dina standardinställningar utan att oavsiktligt rota reflektionskomponenter.
static JsonSerializerOptions GetDefaultOptions()
{
if (JsonSerializer.IsReflectionEnabledByDefault)
{
// This branch has a dependency on DefaultJsonTypeInfo,
// but it will get trimmed away if the feature switch is disabled.
return new()
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower,
}
}
return new() { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower };
}
Kedjekällgeneratorer
Klassen JsonSerializerOptions innehåller en ny TypeInfoResolverChain egenskap som kompletterar den befintliga TypeInfoResolver egenskapen. Dessa egenskaper används i kontraktsanpassning för länkning av källgeneratorer. Tillägget av den nya egenskapen innebär att du inte behöver ange alla länkade komponenter på en anropsplats – de kan läggas till i efterhand.
TypeInfoResolverChain låter dig också introspekta kedjan eller ta bort komponenter från den. Följande kodfragment visar ett exempel.
var options = new JsonSerializerOptions
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(
ContextA.Default, ContextB.Default, ContextC.Default);
};
options.TypeInfoResolverChain.Count; // 3
options.TypeInfoResolverChain.RemoveAt(0);
options.TypeInfoResolverChain.Count; // 2
Core .NET-bibliotek
Det här avsnittet innehåller följande underavsnitt:
- Tidsabstraktion
- UTF8-förbättringar
- Metoder för att arbeta med slumpmässighet
- Prestandafokuserade typer
- System.Numerics och System.Runtime.Intrinsics
- Dataverifiering
Tidsabstraktion
Den nya TimeProvider klassen och ITimer gränssnittet lägger till funktioner för tidsabstraktion , vilket gör att du kan simulera tid i testscenarier. Dessutom kan du använda tidsabstraktionen för att simulera Task åtgärder som förlitar sig på tidsförlopp med hjälp av Task.Delay och Task.WaitAsync. Tidsabstraktionen stöder följande viktiga tidsåtgärder:
- Hämta lokal tid och UTC-tid
- Hämta en tidsstämpel för att mäta prestanda
- Skapa en timer
Följande kodfragment visar några användningsexempel.
// Get system time.
DateTimeOffset utcNow = TimeProvider.System.GetUtcNow();
DateTimeOffset localNow = TimeProvider.System.GetLocalNow();
// Create a time provider that works with a
// time zone that's different than the local time zone.
private class ZonedTimeProvider : TimeProvider
{
private TimeZoneInfo _zoneInfo;
public ZonedTimeProvider(TimeZoneInfo zoneInfo) : base()
{
_zoneInfo = zoneInfo ?? TimeZoneInfo.Local;
}
public override TimeZoneInfo LocalTimeZone => _zoneInfo;
public static TimeProvider FromLocalTimeZone(TimeZoneInfo zoneInfo) =>
new ZonedTimeProvider(zoneInfo);
}
// Create a timer using a time provider.
ITimer timer = timeProvider.CreateTimer(callBack, state, delay, Timeout.InfiniteTimeSpan);
// Measure a period using the system time provider.
long providerTimestamp1 = TimeProvider.System.GetTimestamp();
long providerTimestamp2 = TimeProvider.System.GetTimestamp();
var period = GetElapsedTime(providerTimestamp1, providerTimestamp2);
UTF8-förbättringar
Om du vill aktivera skrivning av en strängliknande representation av din typ till ett målintervall implementerar du det nya IUtf8SpanFormattable gränssnittet för din typ. Det här nya gränssnittet är nära relaterat till , men riktar sig till ISpanFormattableUTF8 och Span<byte>
i stället för UTF16 och Span<char>
.
IUtf8SpanFormattablehar implementerats på alla primitiva typer (plus andra), med exakt samma delade logik oavsett om du har , string
Span<char>
eller Span<byte>
. Det har fullt stöd för alla format (inklusive den nya binära B-specificeraren) och alla kulturer. Det innebär att du nu kan formatera direkt till UTF8 från Byte
, Complex
, Char
, DateOnly
, DateTimeOffset
Guid
Double
Decimal
DateTime
, Half
, , IPAddress
, IPNetwork
Int64
Int16
Int128
IntPtr
Int32
, NFloat
, TimeOnly
Single
SByte
Rune
, TimeSpan
, UInt16
, UInt32
UInt64
, UInt128
, UIntPtr
och .Version
Nya Utf8.TryWrite metoder ger en UTF8-baserad motsvarighet till de befintliga MemoryExtensions.TryWrite metoderna, som är UTF16-baserade. Du kan använda interpolerad strängsyntax för att formatera ett komplext uttryck direkt till ett intervall med UTF8-byte, till exempel:
static bool FormatHexVersion(
short major,
short minor,
short build,
short revision,
Span<byte> utf8Bytes,
out int bytesWritten) =>
Utf8.TryWrite(
utf8Bytes,
CultureInfo.InvariantCulture,
$"{major:X4}.{minor:X4}.{build:X4}.{revision:X4}",
out bytesWritten);
Implementeringen identifierar IUtf8SpanFormattable formatvärdena och använder deras implementeringar för att skriva utf8-representationer direkt till målintervallet.
Implementeringen använder också den nya Encoding.TryGetBytes(ReadOnlySpan<Char>, Span<Byte>, Int32) metoden, som tillsammans med dess Encoding.TryGetChars(ReadOnlySpan<Byte>, Span<Char>, Int32) motsvarighet stöder kodning och avkodning till ett målintervall. Om intervallet inte är tillräckligt långt för att hålla det resulterande tillståndet returnerar false
metoderna i stället för att utlösa ett undantag.
Metoder för att arbeta med slumpmässighet
Typerna System.Random och System.Security.Cryptography.RandomNumberGenerator introducerar två nya metoder för att arbeta med slumpmässighet.
GetItems<T>()
Med de nya System.Random.GetItems metoderna och System.Security.Cryptography.RandomNumberGenerator.GetItems kan du slumpmässigt välja ett angivet antal objekt från en indatauppsättning. Följande exempel visar hur du använder System.Random.GetItems<T>()
(på den instans som tillhandahålls av Random.Shared egenskapen) för att slumpmässigt infoga 31 objekt i en matris. Det här exemplet kan användas i ett spel med "Simon" där spelarna måste komma ihåg en sekvens med färgade knappar.
private static ReadOnlySpan<Button> s_allButtons = new[]
{
Button.Red,
Button.Green,
Button.Blue,
Button.Yellow,
};
// ...
Button[] thisRound = Random.Shared.GetItems(s_allButtons, 31);
// Rest of game goes here ...
Blanda<T>()
Med de nya Random.Shuffle metoderna och RandomNumberGenerator.Shuffle<T>(Span<T>) kan du randomisera ordningen på ett spann. Dessa metoder är användbara för att minska träningsfördomar inom maskininlärning (så det första är inte alltid träning och det sista testet alltid).
YourType[] trainingData = LoadTrainingData();
Random.Shared.Shuffle(trainingData);
IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData);
DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData);
model = chain.Fit(split.TrainSet);
IDataView predictions = model.Transform(split.TestSet);
// ...
Prestandafokuserade typer
.NET 8 introducerar flera nya typer som syftar till att förbättra appprestanda.
Det nya System.Collections.Frozen namnområdet innehåller samlingstyperna FrozenDictionary<TKey,TValue> och FrozenSet<T>. Dessa typer tillåter inte några ändringar av nycklar och värden när en samling har skapats. Det kravet möjliggör snabbare läsåtgärder (till exempel
TryGetValue()
). Dessa typer är särskilt användbara för samlingar som fylls i vid första användningen och sedan sparas under en långlivad tjänst, till exempel:private static readonly FrozenDictionary<string, bool> s_configurationData = LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true); // ... if (s_configurationData.TryGetValue(key, out bool setting) && setting) { Process(); }
Den nya System.Buffers.IndexOfAnyValues<T> typen är utformad för att skickas till metoder som letar efter den första förekomsten av ett värde i den skickade samlingen. Söker till exempel String.IndexOfAny(Char[]) efter den första förekomsten av ett tecken i den angivna matrisen i den
string
som anropas. NET 8 lägger till nya överlagringar av metoder som String.IndexOfAny och MemoryExtensions.IndexOfAny som accepterar en instans av den nya typen. När du skapar en instans av System.Buffers.IndexOfAnyValues<T>härleds alla data som behövs för att optimera efterföljande sökningar vid den tidpunkten, vilket innebär att arbetet utförs i förväg.Den nya System.Text.CompositeFormat typen är användbar för att optimera formatsträngar som inte är kända vid kompileringen (till exempel om formatsträngen läses in från en resursfil). Lite extra tid ägnas åt att utföra arbete som att parsa strängen, men det sparar arbetet från att utföras vid varje användning.
private static readonly CompositeFormat s_rangeMessage = CompositeFormat.Parse(LoadRangeMessageResource()); // ... static string GetMessage(int min, int max) => string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max);
Nya System.IO.Hashing.XxHash3 och System.IO.Hashing.XxHash128 typer tillhandahåller implementeringar av de snabba XXH3- och XXH128-hashalgoritmerna.
System.Numerics och System.Runtime.Intrinsics
Det här avsnittet beskriver förbättringar av namnrymderna System.Numerics och System.Runtime.Intrinsics .
- Vector256<T>, Matrix3x2och Matrix4x4 har förbättrat maskinvaruaccelerationen på .NET 8. Till exempel Vector256<T> omimplementerades till internt åtgärder
2x Vector128<T>
, där det var möjligt. Detta möjliggör partiell acceleration av vissa funktioner närVector128.IsHardwareAccelerated == true
menVector256.IsHardwareAccelerated == false
, till exempel på Arm64. - Maskinvaruinbyggda funktioner kommenteras nu med attributet
ConstExpected
. Detta säkerställer att användarna är medvetna om när den underliggande maskinvaran förväntar sig en konstant och därför när ett icke-konstant värde oväntat kan skada prestandan. - API:et Lerp(TSelf, TSelf, TSelf)
Lerp
har lagts till IFloatingPointIeee754<TSelf> i och därför tillfloat
(Single),double
(Double) och Half. Med det här API:et kan en linjär interpolering mellan två värden utföras effektivt och korrekt.
Vector512 och AVX-512
.NET Core 3.0 utökat SIMD-stöd för att inkludera plattformsspecifika maskinvaru-API:er för x86/x64. .NET 5 har lagt till stöd för Arm64 och .NET 7 som har lagt till den plattformsoberoende maskinvaran. .NET 8 ger stöd för SIMD genom att introducera Vector512<T> och stödja instruktioner för Intel Advanced Vector Extensions 512 (AVX-512).
Mer specifikt innehåller .NET 8 stöd för följande viktiga funktioner i AVX-512:
- 512-bitars vektoråtgärder
- Ytterligare 16 SIMD-register
- Ytterligare instruktioner för vektorer med 128 bitar, 256 bitar och 512 bitar
Om du har maskinvara som stöder funktionerna rapporterar true
nu Vector512.IsHardwareAccelerated .
.NET 8 lägger också till flera plattformsspecifika klasser under System.Runtime.Intrinsics.X86 namnområdet:
- Avx512F (grundläggande)
- Avx512BW (byte och ord)
- Avx512CD (konfliktidentifiering)
- Avx512DQ (dubbelord och quadword)
- Avx512Vbmi (instruktioner för bytemanipulering av vektor)
De här klasserna följer samma allmänna form som andra arkitekturer för instruktionsuppsättningar (ISA) eftersom de exponerar en IsSupported egenskap och en kapslad Avx512F.X64 klass för instruktioner som endast är tillgängliga för 64-bitarsprocesser. Dessutom har varje klass en kapslad Avx512F.VL klass som exponerar tilläggen Avx512VL
(vektorlängd) för motsvarande instruktionsuppsättning.
Även om du inte uttryckligen använder Vector512
-specifika eller Avx512F
-specifika instruktioner i din kod, kommer du förmodligen fortfarande att dra nytta av det nya AVX-512-stödet. JIT kan dra nytta av ytterligare register och instruktioner implicit när du använder Vector128<T> eller Vector256<T>. Basklassbiblioteket använder den här maskinvaran internt i de flesta åtgärder som exponeras av Span<T> och ReadOnlySpan<T> i många av de matematiska API:er som exponeras för de primitiva typerna.
Datavalidering
Namnområdet System.ComponentModel.DataAnnotations innehåller nya dataverifieringsattribut avsedda för valideringsscenarier i molnbaserade tjänster. Medan de befintliga DataAnnotations
validerarna är inriktade på typisk validering av UI-datainmatning, till exempel fält i ett formulär, är de nya attributen utformade för att verifiera data som inte kommer in från användaren, till exempel konfigurationsalternativ. Förutom de nya attributen har nya egenskaper lagts till i typerna RangeAttribute och RequiredAttribute .
Nytt API | Description |
---|---|
RequiredAttribute.DisallowAllDefaultValues | Verifierar att structs inte är lika med deras standardvärden. |
RangeAttribute.MinimumIsExclusive RangeAttribute.MaximumIsExclusive |
Anger om gränser ingår i det tillåtna intervallet. |
System.ComponentModel.DataAnnotations.LengthAttribute | Anger både nedre och övre gränser för strängar eller samlingar. Kräver till exempel [Length(10, 20)] minst 10 element och högst 20 element i en samling. |
System.ComponentModel.DataAnnotations.Base64StringAttribute | Verifierar att en sträng är en giltig Base64-representation. |
System.ComponentModel.DataAnnotations.AllowedValuesAttribute System.ComponentModel.DataAnnotations.DeniedValuesAttribute |
Ange listor över tillåtna respektive nekande. Till exempel [AllowedValues("apple", "banana", "mango")] . |
Tilläggsbibliotek
ValidateOptionsResultBuilder-typ
.NET 8 introducerar ValidateOptionsResultBuilder typen för att underlätta skapandet av ett ValidateOptionsResult objekt. Det är viktigt att den här byggaren tillåter ackumulering av flera fel. Tidigare var det svårt att skapa det ValidateOptionsResult objekt som krävs för att implementera IValidateOptions<TOptions>.Validate(String, TOptions) och resulterade ibland i skiktade valideringsfel. Om det fanns flera fel stoppades valideringsprocessen ofta vid det första felet.
Följande kodfragment visar en exempelanvändning av ValidateOptionsResultBuilder.
ValidateOptionsResultBuilder builder = new();
builder.AddError("Error: invalid operation code");
builder.AddResult(ValidateOptionsResult.Fail("Invalid request parameters"));
builder.AddError("Malformed link", "Url");
// Build ValidateOptionsResult object has accumulating multiple errors.
ValidateOptionsResult result = builder.Build();
// Reset the builder to allow using it in new validation operation.
builder.Clear();
Skräpinsamling
.NET 8 lägger till en funktion för att justera minnesgränsen i farten. Detta är användbart i molntjänstscenarier, där efterfrågan kommer och går. För att vara kostnadseffektiva bör tjänsterna skalas upp och ned på resursförbrukningen när efterfrågan varierar. När en tjänst upptäcker en minskning av efterfrågan kan den skala ned resursförbrukningen genom att minska minnesgränsen. Tidigare misslyckades detta eftersom skräpinsamlaren (GC) inte kände till ändringen och kan allokera mer minne än den nya gränsen. Med den här ändringen kan du anropa API:et _RefreshMemoryLimit
för att uppdatera GC med den nya minnesgränsen.
Det finns vissa begränsningar att känna till:
- För tillfället är API:et
_RefreshMemoryLimit
privat, så du måste anropa det via privat reflektion. - På 32-bitarsplattformar (till exempel Windows x86 och Linux ARM) kan .NET inte upprätta en ny heap-hård gräns om det inte redan finns en.
- API:et kan returnera en statuskod som inte är noll som anger att uppdateringen misslyckades. Detta kan inträffa om nedskalningen är för aggressiv och inte lämnar något utrymme för GC att manövrera. I det här fallet bör du överväga att anropa
GC.Collect(2, GCCollectionMode.Aggressive)
för att minska den aktuella minnesanvändningen och försök sedan igen. - Om du skalar upp minnesgränsen utöver den storlek som GC tror att processen kan hantera under starten kommer anropet
_RefreshMemoryLimit
att lyckas, men det kommer inte att kunna använda mer minne än vad den uppfattar som gränsen.
Följande kodfragment visar hur du anropar API:et med reflektion.
MethodInfo refreshMemoryLimitMethod = typeof(GC).GetMethod(
"_RefreshMemoryLimit", BindingFlags.NonPublic | BindingFlags.Static);
refreshMemoryLimitMethod.Invoke(null, Array<object>.Empty);
Du kan också uppdatera några av GC-konfigurationsinställningarna som är relaterade till minnesgränsen. Följande kodfragment anger den hårda heapgränsen till 100 mebibyte (MiB):
AppContext.SetData("GCHeapHardLimit", (ulong)100 * 1024 * 1024);
MethodInfo refreshMemoryLimitMethod = typeof(GC).GetMethod(
"_RefreshMemoryLimit", BindingFlags.NonPublic | BindingFlags.Static);
refreshMemoryLimitMethod.Invoke(null, Array<object>.Empty);
Källgenerator för konfigurationsbindning
ASP.NET Core använder konfigurationsproviders för att utföra appkonfiguration. Leverantörerna läser nyckel/värde-pardata från olika källor, till exempel inställningsfiler, miljövariabler och Azure Key Vault. ConfigurationBinder är den typ som mappar konfigurationsvärden till starkt typifierade objekt. Tidigare utfördes mappningen med reflektion, vilket kan orsaka problem för trimning och intern AOT. Från och med .NET 8 kan du välja att använda en källgenerator för att generera bindningsimplementeringarna. Generatoravsökningarna för Configure(TOptions), Bindoch Get anropar för att hämta typinformation från. När generatorn är aktiverad i ett projekt väljer kompilatorn implicit genererade metoder framför de befintliga reflektionsbaserade ramverksimplementeringarna.
Om du vill välja källgeneratorn anger du EnableMicrosoftExtensionsConfigurationBinderSourceGenerator
egenskapen till true
i projektfilen:
<PropertyGroup>
<EnableMicrosoftExtensionsConfigurationBinderSourceGenerator>
true
</EnableMicrosoftExtensionsConfigurationBinderSourceGenerator>
</PropertyGroup>
Du måste också ladda ned den senaste förhandsversionen av NuGet-paketet Microsoft.Extensions.Configuration.Binder.
Följande kod visar ett exempel på hur du anropar bindemedlet.
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
IConfigurationSection section = builder.Configuration.GetSection("MyOptions");
// !! Configure call - to be replaced with source-gen'd implementation
builder.Services.Configure<MyOptions>(section);
// !! Get call - to be replaced with source-gen'd implementation
MyOptions options0 = section.Get<MyOptions>();
// !! Bind call - to be replaced with source-gen'd implementation
MyOptions options1 = new MyOptions();
section.Bind(myOptions1);
WebApplication app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
public class MyOptions
{
public int A { get; set; }
public string S { get; set; }
public byte[] Data { get; set; }
public Dictionary<string, string> Values { get; set; }
public List<MyClass> Values2 { get; set; }
}
public class MyClass
{
public int SomethingElse { get; set; }
}
Reflektionsförbättringar
Funktionspekare introducerades i .NET 5, men motsvarande stöd för reflektion lades inte till vid den tidpunkten. När du använder typeof
eller reflekterar en funktionspekare, till exempel typeof(delegate*<void>())
eller FieldInfo.FieldType
, returnerades en IntPtr . Från och med .NET 8 returneras ett System.Type objekt i stället. Den här typen ger åtkomst till metadata för funktionspekare, inklusive anropskonventioner, returtyp och parametrar.
Anteckning
En funktionspekarinstans, som är en fysisk adress till en funktion, fortsätter att representeras som en IntPtr. Endast reflektionstypen har ändrats.
Den nya funktionen implementeras för närvarande endast i CoreCLR-körningen och MetadataLoadContext.
Nya API:er har lagts till i , till System.Typeexempel IsFunctionPointer, och i System.Reflection.PropertyInfo, System.Reflection.FieldInfooch System.Reflection.ParameterInfo. Följande kod visar hur du använder några av de nya API:erna för reflektion.
// Sample class that contains a function pointer field.
public unsafe class UClass
{
public delegate* unmanaged[Cdecl, SuppressGCTransition]<in int, void> _fp;
}
// ...
FieldInfo fieldInfo = typeof(UClass).GetField(nameof(UClass._fp));
// Obtain the function pointer type from a field.
Type fpType = fieldInfo.FieldType;
// New methods to determine if a type is a function pointer.
Console.WriteLine($"IsFunctionPointer: {fpType.IsFunctionPointer}");
Console.WriteLine($"IsUnmanagedFunctionPointer: {fpType.IsUnmanagedFunctionPointer}");
// New methods to obtain the return and parameter types.
Console.WriteLine($"Return type: {fpType.GetFunctionPointerReturnType()}");
foreach (Type parameterType in fpType.GetFunctionPointerParameterTypes())
{
Console.WriteLine($"Parameter type: {parameterType}");
}
// Access to custom modifiers and calling conventions requires a "modified type".
Type modifiedType = fieldInfo.GetModifiedFieldType();
// A modified type forwards most members to its underlying type.
Type normalType = modifiedType.UnderlyingSystemType;
// New method to obtain the calling conventions.
foreach (Type callConv in modifiedType.GetFunctionPointerCallingConventions())
{
Console.WriteLine($"Calling convention: {callConv}");
}
// New method to obtain the custom modifiers.
foreach (Type modreq in modifiedType.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers())
{
Console.WriteLine($"Required modifier for first parameter: {modreq}");
}
I föregående exempel skapas följande utdata:
IsFunctionPointer: True
IsUnmanagedFunctionPointer: True
Return type: System.Void
Parameter type: System.Int32&
Calling convention: System.Runtime.CompilerServices.CallConvSuppressGCTransition
Calling convention: System.Runtime.CompilerServices.CallConvCdecl
Required modifier for first parameter: System.Runtime.InteropServices.InAttribute
Inbyggt AOT-stöd
Alternativet att publicera som intern AOT introducerades först i .NET 7. Om du publicerar en app med inbyggd AOT skapas en helt fristående version av din app som inte behöver en körning – allt ingår i en enda fil. .NET 8 ger följande förbättringar av intern AOT-publicering:
Lägger till stöd för x64- och Arm64-arkitekturerna på macOS.
Minskar storleken på interna AOT-appar i Linux med upp till 50 %. I följande tabell visas storleken på en "Hello World"-app som publicerats med intern AOT som innehåller hela .NET-körningen på .NET 7 jämfört med .NET 8:
Operativsystem .NET 7 .NET 8 Linux x64 (med -p:StripSymbols=true
)3,76 MB 1,84 MB Windows x64 2,85 MB 1,77 MB Gör att du kan ange en optimeringsinställning: storlek eller hastighet. Som standard väljer kompilatorn att generera snabb kod samtidigt som den är medveten om programmets storlek. Du kan dock använda
<OptimizationPreference>
egenskapen MSBuild för att optimera specifikt för den ena eller den andra. Mer information finns i Optimera AOT-distributioner.
Mall för konsolapp
Standardmallen för konsolappen innehåller nu stöd för AOT direkt. Om du vill skapa ett projekt som har konfigurerats för AOT-kompilering kör dotnet new console --aot
du bara . Projektkonfigurationen som läggs till av --aot
har tre effekter:
- Genererar en intern fristående körbar fil med inbyggd AOT när du publicerar projektet, till exempel med
dotnet publish
eller Visual Studio. - Aktiverar kompatibilitetsanalysverktyg för trimning, AOT och enskild fil. De här analysverktygen varnar dig om potentiellt problematiska delar av projektet (om det finns några).
- Aktiverar felsökningstidsemulering av AOT så att du får en liknande upplevelse som AOT när du felsöker projektet utan AOT-kompilering. Om du till exempel använder System.Reflection.Emit i ett NuGet-paket som inte har kommenterats för AOT (och därför missades av kompatibilitetsanalysen) innebär emuleringen att du inte får några överraskningar när du försöker publicera projektet med AOT.
Prestandaförbättringar
.NET 8 innehåller förbättringar av kodgenerering och jit-kompilering (just-in-time):
- Prestandaförbättringar för Arm64
- SIMD-förbättringar
- Stöd för AVX-512 ISA-tillägg (se Vector512 och AVX-512)
- Molnbaserade förbättringar
- Förbättringar av profilstyrd optimering (PGO)
- Förbättringar av JIT-dataflöde
- Loop och allmänna optimeringar
- Optimerad åtkomst för fält som markerats med ThreadStaticAttribute
- På varandra följande registerallokering. Arm64 har två instruktioner för tabellvektorsökning, som kräver att alla entiteter i deras tupplar finns i på varandra följande register.
- JIT/NativeAOT kan nu avregistrera och automatiskt vektorisera vissa minnesåtgärder med SIMD, till exempel jämförelse, kopiering och nollning, om det kan fastställa deras storlekar vid kompileringstidpunkten.
.NET-containeravbildningar
Följande ändringar har gjorts i .NET-containeravbildningar för .NET 8:
- Debian 12
- Icke-rotanvändare
- Förhandsgranska bilder
- Mejslade Ubuntu-bilder
- Skapa containeravbildningar för flera plattformar
Debian 12
Containeravbildningarna använder nu Debian 12 (Bookworm). Debian är standarddistributionen av Linux i .NET-containeravbildningarna.
Icke-rotanvändare
Bilder inkluderar en non-root
användare. Den här användaren gör bilderna non-root
kompatibla. Om du vill köra som non-root
lägger du till följande rad i slutet av Dockerfile (eller en liknande instruktion i Kubernetes-manifesten):
USER app
.NET 8 lägger till en miljövariabel för UID för non-root
användaren, vilket är 64198. Den här miljövariabeln är användbar för Kubernetes-testet runAsNonRoot
, vilket kräver att containeranvändaren anges via UID och inte efter namn. Den här dockerfile visar en exempelanvändning.
Standardporten ändrades också från port 80
till 8080
. För att stödja den här ändringen är en ny miljövariabel ASPNETCORE_HTTP_PORTS
tillgänglig för att göra det enklare att ändra portar. Variabeln accepterar en lista med portar, vilket är enklare än det format som krävs av ASPNETCORE_URLS
. Om du ändrar porten tillbaka till porten 80
med någon av dessa variabler kan du inte köra som non-root
.
Förhandsgranska bilder
Taggar för förhandsgranskningscontaineravbildningar har nu ett -preview
suffix i stället för att bara använda versionsnumret. Om du till exempel vill hämta .NET 8 Preview SDK använder du följande tagg:
docker run --rm -it mcr.microsoft.com/dotnet/sdk:8.0-preview
Suffixet -preview
tas bort för versionskandidatversioner (RC).
Mejslade Ubuntu-bilder
Mejslade Ubuntu-avbildningar är tillgängliga för .NET 8. Mejslade bilder har en reducerad attackerad yta eftersom de är ultra-små, inte har någon pakethanterare eller gränssnitt och är non-root
. Den här typen av avbildning är till för utvecklare som vill ha nytta av datoranvändning i installationsstil. Mejslade avbildningar publiceras i .NET:s nattliga artefaktregister.
Skapa containeravbildningar för flera plattformar
Docker har stöd för att använda och skapa plattformsoberoende avbildningar som fungerar i flera miljöer. .NET 8 introducerar ett nytt mönster som gör att du kan blanda och matcha arkitekturer med de .NET-avbildningar som du skapar. Om du till exempel använder macOS och vill rikta in dig på en x64-molntjänst i Azure kan du skapa avbildningen med hjälp av växeln --platform
på följande sätt:
docker build --pull -t app --platform linux/amd64
.NET SDK stöder $TARGETARCH
nu värden och -a
argumentet vid återställning. Följande kodfragment visar ett exempel:
RUN dotnet restore -a $TARGETARCH
# Copy everything else and build app.
COPY aspnetapp/. .
RUN dotnet publish -a $TARGETARCH --self-contained false --no-restore -o /app
Mer information finns i blogginlägget Förbättra stöd för flerplattformscontainer .
.NET på Linux
Lägsta stödbaslinjer för Linux
Minsta stödbaslinjer för Linux har uppdaterats för .NET 8. .NET har skapats för Ubuntu 16.04 för alla arkitekturer. Det är främst viktigt för att definiera den lägsta glibc
versionen för .NET 8. .NET 8 startar inte på distributionsversioner som innehåller en äldre glibc, till exempel Ubuntu 14.04 eller Red Hat Enterprise Linux 7.
Mer information finns i Stöd för Red Hat Enterprise Linux-familjen.
Skapa din egen .NET på Linux
I tidigare .NET-versioner kunde du skapa .NET från källan, men du måste skapa en "källtarball" från dotnet/installer-lagringsplatsen som motsvarar en version. I .NET 8 är det inte längre nödvändigt och du kan skapa .NET på Linux direkt från dotnet-/dotnet-lagringsplatsen . Den lagringsplatsen använder dotnet/source-build för att skapa .NET-runtimes, verktyg och SDK:er. Det här är samma version som Red Hat och Canonical använder för att skapa .NET.
Att skapa i en container är den enklaste metoden för de flesta eftersom containeravbildningarna dotnet-buildtools/prereqs
innehåller alla nödvändiga beroenden. Mer information finns i bygginstruktionerna.
NuGet
Från och med .NET 8 verifierar NuGet signerade paket i Linux som standard. NuGet fortsätter även att verifiera signerade paket i Windows.
De flesta användare bör inte märka verifieringen. Men om du har ett befintligt rotcertifikatpaket som finns på /etc/pki/ca-trust/extracted/pem/objsign-ca-bundle.pem, kan du se förtroendefel tillsammans med varning nu3042.
Du kan välja bort verifiering genom att ange miljövariabeln DOTNET_NUGET_SIGNATURE_VERIFICATION
till false
.