Aracılığıyla paylaş


.NET 8 çalışma zamanındaki yenilikler

Bu makalede.NET 8 için .NET çalışma zamanındaki yeni özellikler açıklanmaktadır.

Performans iyileştirmeleri

.NET 8, kod oluşturma ve tam zamanında (JIT) derleme geliştirmeleri içerir:

  • Arm64 performans geliştirmeleri
  • SIMD geliştirmeleri
  • AVX-512 ISA uzantıları desteği (bkz . Vector512 ve AVX-512)
  • Bulutta yerel iyileştirmeler
  • JIT aktarım hızı geliştirmeleri
  • Döngü ve genel iyileştirmeler
  • ile işaretlenmiş alanlar için iyileştirilmiş erişim ThreadStaticAttribute
  • Ardışık kayıt ayırma. Arm64'te tablo vektör taraması için iki yönerge vardır ve bunlar, demet işlenenlerindeki tüm bileşenlerin ardışık yazmaçlarda bulunmasını gerektirir.
  • JIT/NativeAOT, derleme zamanında boyutlarını belirleyebildiği takdirde, karşılaştırma, kopyalama ve sıfırlama gibi bazı bellek işlemlerini açabilir ve SIMD ile otomatik olarak vektörleştirebilir.

Buna ek olarak, dinamik profil destekli iyileştirme (PGO) geliştirilmiştir ve artık varsayılan olarak etkindir. Artık etkinleştirmek için çalışma zamanı yapılandırma seçeneğini kullanmanız gerekmez. Dinamik PGO, sıfırıncı katman sırasında eklenen ek enstrümantasyona dayalı olarak kodu daha da optimize etmek için katmanlı derleme süreciyle birlikte çalışır.

Ortalama olarak, dinamik PGO performansı yaklaşık 15%artırır. Yaklaşık 4600 test içeren bir kıyaslama paketinde 23% 20% veya daha fazla performans iyileştirmesi gördü.

Codegen yapısı yükseltme

.NET 8, JIT'nin yapı değişkenlerini yükseltme yeteneğini genelleştiren kod oluşturma için yeni bir fiziksel yükseltme iyileştirme geçişi içerir. Bu iyileştirme ( toplamların skaler değişimi olarak da adlandırılır), yapı değişkenlerinin alanlarını JIT'nin daha sonra mantık oluşturabileceği ve daha hassas bir şekilde iyileştirebileceği ilkel değişkenlerle değiştirir.

JIT bu iyileştirmeyi zaten desteklese de aşağıdakiler dahil olmak üzere çeşitli büyük sınırlamalar içerir:

  • Yalnızca dört veya daha az alana sahip yapılar için destekleniyordu.
  • Yalnızca her alan ilkel bir türse veya basit bir yapı ilkel türü sarmalarsa desteklenir.

Fiziksel yükseltme, uzun süredir devam eden JIT sorunlarını düzelten bu sınırlamaları kaldırır.

Çöp toplama

.NET 8, bellek sınırını anında ayarlama özelliği ekler. Bu, talebin gelip gittiği bulut hizmeti senaryolarında kullanışlıdır. Maliyet etkin olması için, talep dalgalanmaları nedeniyle hizmetlerin kaynak tüketiminde ölçeği artırması ve azaltması gerekir. Bir hizmet talepte bir azalma algıladığında bellek sınırını azaltarak kaynak tüketiminin ölçeğini azaltabilir. Daha önce, çöp toplayıcı (GC) değişikliğin farkında olmadığından ve yeni sınırdan daha fazla bellek ayırabileceğinden bu başarısız olacaktı. Bu değişiklikle API'yi çağırarak RefreshMemoryLimit() GC'yi yeni bellek sınırıyla güncelleştirebilirsiniz.

Dikkat edilmesi gereken bazı sınırlamalar vardır:

  • 32 bit platformlarda (örneğin, Windows x86 ve Linux ARM), daha önce belirlenmemişse .NET yeni bir yığın sert sınırı oluşturamaz.
  • API, yenilemenin başarısız olduğunu gösteren sıfır olmayan bir durum kodu döndürebilir. Ölçek küçültme çok agresifse ve GC'nin manevra yapabilmesi için yer bırakmazsa bu durum oluşabilir. Bu durumda, geçerli bellek kullanımını küçültmek için GC.Collect(2, GCCollectionMode.Aggressive) çağrısını göz önünde bulundurun ve sonra yeniden deneyin.
  • Başlangıç sırasında RefreshMemoryLimit GC'nin işlemin işleyebileceğine inandığı boyutun ötesinde bellek sınırını genişletirseniz çağrı başarılı olur, ancak sınır olarak algılanandan daha fazla bellek kullanamaz.

Aşağıdaki kod parçacığıNDA API'nin nasıl çağrılacakları gösterilmektedir.

GC.RefreshMemoryLimit();

Bellek sınırıyla ilgili GC yapılandırma ayarlarının bazılarını da yenileyebilirsiniz. Aşağıdaki kod parçacığı yığın sabit sınırını 100 mebibayt (MiB) olarak ayarlar:

AppContext.SetData("GCHeapHardLimit", (ulong)100 * 1_024 * 1_024);
GC.RefreshMemoryLimit();

API, sabit sınır geçersizse, örneğin negatif yığın sabit sınırı yüzdeleri ve sabit sınırın çok düşük olması durumunda, bir InvalidOperationException fırlatabilir. Yeni AppData ayarları nedeniyle veya kapsayıcı bellek sınırı değişiklikleri nedeniyle yenilemenin ayarlanacağı yığın sabit sınırı önceden kaydedilmiş olandan daha düşükse bu durum oluşabilir.

Mobil uygulamalar için genelleştirme

iOS, tvOS ve MacCatalyst'teki mobil uygulamalar, daha hafif bir ICU paketi kullanan yeni bir hibrit küreselleştirme modunu tercih edebilir. Karma modda genelleştirme verileri kısmen ICU paketinden, kısmen de Yerel API'lere yapılan çağrılardan alınır. Hibrit mod, mobil cihazlar tarafından desteklenen tüm yerel ayarlara hizmet eder.

Hibrit mod, değişmez küreselleştirme modunda çalışamayan ve mobildeki ICU verilerinden kesilen kültürleri kullanan uygulamalar için en uygunudur. Daha küçük bir ICU veri dosyası yüklemek istediğinizde de kullanabilirsiniz. (icudt_hybrid.dat dosyası, varsayılan ICU veri dosyası icudt.dat'tan %34,5 daha küçüktür.)

Karma genelleştirme modunu kullanmak için MSBuild özelliğini true olarak ayarlayın HybridGlobalization :

<PropertyGroup>
  <HybridGlobalization>true</HybridGlobalization>
</PropertyGroup>

Dikkat edilmesi gereken bazı sınırlamalar vardır:

  • Yerel API'nin sınırlamaları nedeniyle tüm genelleştirme API'leri karma modda desteklenmez.
  • Desteklenen API'lerden bazıları farklı davranışlara sahiptir.

Uygulamanızın etkilenip etkilenmediğini denetlemek için bkz. Davranış farklılıkları.

Kaynak tarafından oluşturulan COM birlikte çalışma

.NET 8, COM arabirimleriyle birlikte çalışma desteği sağlayan yeni bir kaynak oluşturucu içerir. Bir arabirimi kaynak oluşturucu için COM arabirimi olarak işaretlemek için kullanabilirsiniz GeneratedComInterfaceAttribute . Kaynak oluşturucu daha sonra C# kodundan yönetilmeyen koda çağrıyı etkinleştirmek için kod oluşturur. Ayrıca yönetilmeyen koddan C# içine çağrıyı etkinleştirmek için kod oluşturur. Bu kaynak oluşturucu LibraryImportAttribute ile bütünleşir ve GeneratedComInterfaceAttribute türlerini parametre ve dönüş türleri olarak LibraryImport özellikli yöntemlerde kullanabilirsiniz.

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

[GeneratedComInterface]
[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]
partial interface IComInterface
{
    void DoWork();
}

internal partial class MyNativeLib
{
    [LibraryImport(nameof(MyNativeLib))]
    public static partial void GetComInterface(out IComInterface comInterface);
}

Kaynak oluşturucu, ayrıca GeneratedComClassAttribute özniteliğiyle arabirimleri uygulayan türleri yönetilmeyen koda geçirmenizi sağlamak için yeni GeneratedComInterfaceAttribute özniteliğini de destekler. Kaynak oluşturucu, arabirimleri uygulayan ve çağrıları yönetilen uygulamaya ileden bir COM nesnesini kullanıma açmak için gereken kodu oluşturur.

özniteliğine GeneratedComInterfaceAttribute sahip arabirimlerdeki yöntemler, LibraryImportAttribute ile aynı türleri destekler ve artık LibraryImportAttribute, GeneratedComInterface-attributed türlerini ve GeneratedComClass-attributed türlerini desteklemektedir.

C# kodunuz, bir COM nesnesini yönetilmeyen koddan sarmak için yalnızca GeneratedComInterface-ilişkilendirilmiş arabirimi kullanıyorsa yahut bir yönetilen nesneyi C# dilinden sarmalayıp yönetilmeyen koda açıyorsa, Options özelliğinde bulunan seçenekler ile hangi kodun oluşturulacağını özelleştirebilirsiniz. Bu seçenekler, kullanılmayacağını bildiğiniz senaryolar için marshaller yazmanız gerekmeyeceği anlamına gelir.

Kaynak oluşturucu, COM nesne sarmalayıcılarını ve yönetilen nesne sarmalayıcılarını oluşturmak ve yönetmek için yeni StrategyBasedComWrappers türü kullanır. Bu yeni tür, COM birlikte çalışma için beklenen .NET kullanıcı deneyimini sağlarken ileri düzey kullanıcılar için özelleştirme noktaları sağlar. Uygulamanızın COM'dan türleri tanımlamak için kendi mekanizması varsa veya kaynak tarafından oluşturulan COM'un şu anda desteklemediği senaryoları desteklemeniz gerekiyorsa, senaryonuz için eksik özellikleri eklemek ve COM türleriniz için aynı .NET kullanıcı deneyimini elde etmek için yeni StrategyBasedComWrappers türü kullanmayı göz önünde bulundurun.

Visual Studio kullanıyorsanız yeni çözümleyiciler ve kod düzeltmeleri, mevcut COM birlikte çalışma kodunuzu kaynak tarafından oluşturulan birlikte çalışma özelliğini kullanacak şekilde dönüştürmenizi kolaylaştırır. olan her arabirimin ComImportAttributeyanında bir ampul, kaynak tarafından oluşturulan birlikte çalışabilirliğe dönüştürme seçeneği sunar. Düzeltme, arayüzü GeneratedComInterfaceAttribute özniteliğini kullanacak şekilde değiştirir. Her sınıfın yanında, GeneratedComInterfaceAttribute bir arayüz uygulayan, bir ampul GeneratedComClassAttribute özniteliğini türüne ekleme seçeneği sunar. Türleriniz dönüştürüldükten sonra, DllImport yöntemlerinizi LibraryImportAttribute kullanacak şekilde taşıyabilirsiniz.

Sınırlamalar

COM kaynak oluşturucu, bir COM CoClass'ı etkinleştirmek için new anahtar sözcüğünü ve aşağıdaki API'leri kullanarak apartman yalıtımını desteklemez.

Yapılandırma bağlama kaynak oluşturucu

.NET 8, ASP.NET Core'da AOT ve kırpma dostu yapılandırma sağlamak için bir kaynak oluşturucu sunar. Oluşturucu, önceden var olan yansıma tabanlı uygulamaya bir alternatiftir.

Kaynak oluşturucu, Configure(TOptions), Bind ve Get çağrılarını tür bilgilerini almak için araştırır. Oluşturucu bir projede etkinleştirildiğinde, derleyici önceden var olan yansıma tabanlı çerçeve uygulamaları yerine oluşturulan yöntemleri örtük olarak seçer.

Oluşturucuyu kullanmak için kaynak kodu değişikliği gerekmez. AOT ile derlenen web uygulamaları ve PublishTrimmed değerinin true olarak ayarlandığı (.NET 8+ uygulamaları) durumlarında varsayılan olarak etkinleştirilir. Diğer proje türleri için kaynak oluşturucu varsayılan olarak devre dışıdır, ancak proje dosyanızda EnableConfigurationBindingGenerator özelliğini true olarak ayarlayarak etkinleştirebilirsiniz.

<PropertyGroup>
    <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
</PropertyGroup>

Aşağıdaki kod, bağlayıcıyı çağırma örneğini gösterir.

public class ConfigBindingSG
{
    static void RunIt(params string[] args)
    {
        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();
        section.Bind(options1);

        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; }
    }
}

Çekirdek .NET kitaplıkları

Bu bölüm aşağıdaki alt konuları içerir:

Reflection

İşlev işaretçileri .NET 5'te tanıtıldı, ancak ilgili yansıma desteği o sırada eklenmedi. typeof veya işlev işaretçisinde yansıma kullanılırken, örneğin typeof(delegate*<void>()) veya FieldInfo.FieldType kullanıldığında, sırasıyla bir IntPtr döndürüldü. .NET 8'den başlayarak, bunun yerine bir System.Type nesne döndürülür. Bu tür, çağırma kuralları, dönüş türü ve parametreler dahil olmak üzere işlev işaretçisi meta verilerine erişim sağlar.

Uyarı

bir işlevin fiziksel adresi olan işlev işaretçisi örneği, olarak IntPtrtemsil edilmeye devam eder. Yalnızca yansıma türü değişti.

Yeni işlevsellik şu anda yalnızca CoreCLR çalışma zamanı ve MetadataLoadContextiçinde uygulandı.

Yeni API'ler, System.Type gibi, IsFunctionPointer ve System.Reflection.PropertyInfo, System.Reflection.FieldInfo ve System.Reflection.ParameterInfo gibi öğelere eklendi. Aşağıdaki kod, yansıma için bazı yeni API'lerin nasıl kullanılacağını gösterir.

using System;
using System.Reflection;

// Sample class that contains a function pointer field.
public unsafe class UClass
{
    public delegate* unmanaged[Cdecl, SuppressGCTransition]<in int, void> _fp;
}

internal class FunctionPointerReflection
{
    public static void RunIt()
    {
        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()}");

        if (fpType is not null)
        {
            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;

        if (modifiedType is not null)
        {
            // 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.
        Type[]? modifiers =
            modifiedType?.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers();

        if (modifiers is not null)
        {
            foreach (Type modreq in modifiers)
            {
                Console.WriteLine($"Required modifier for first parameter: {modreq}");
            }
        }
    }
}

Önceki örnek aşağıdaki çıkışı oluşturur:

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

Serialization

.NET 8'de serileştirme ve seri durumdan çıkarma işlevselliğinde birçok geliştirme yapılmıştır System.Text.Json . Örneğin, POCO'da olmayan JSON özelliklerinin işlenmesini özelleştirebilirsiniz.

Aşağıdaki bölümlerde diğer serileştirme geliştirmeleri açıklanmaktadır:

Genel olarak JSON serileştirmesi hakkında daha fazla bilgi için bkz. .NET'te JSON serileştirme ve seri durumdan çıkarma.

Ek türler için yerleşik destek

Seri hale getirici aşağıdaki ek türler için yerleşik desteğe sahiptir.

  • Half, Int128ve UInt128 sayısal türler.

    Console.WriteLine(JsonSerializer.Serialize(
        [ Half.MaxValue, Int128.MaxValue, UInt128.MaxValue ]
    ));
    // [65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]
    
  • Memory<T> ve ReadOnlyMemory<T> değerlerini seçin. byte değerleri Base64 dizelerine, diğer türler ise JSON dizilerine serileştirilir.

    JsonSerializer.Serialize<ReadOnlyMemory<byte>>(new byte[] { 1, 2, 3 }); // "AQID"
    JsonSerializer.Serialize<Memory<int>>(new int[] { 1, 2, 3 }); // [1,2,3]
    

Kaynak oluşturucu

.NET 8, System.Text.Json kaynak oluşturucusununYansıma tabanlı seri hale getirici ile aynı yerel AOT deneyimini oluşturmayı hedefleyen geliştirmeleri içerir. Örneğin:

  • Kaynak oluşturucu artık required ve init özelliklerine sahip türleri serileştirmeyi destekliyor. Bunların ikisi de yansıma tabanlı serileştirmede zaten destekleniyordu.

  • Kaynak tarafından oluşturulan kodun biçimlendirmesi geliştirildi.

  • JsonSourceGenerationOptionsAttribute ile JsonSerializerOptionsözellik eşliği. Daha fazla bilgi için bkz . Seçenekleri belirtme (kaynak oluşturma).

  • Ek tanılamalar ( SYSLIB1034 ve SYSLIB1039 gibi).

  • Yoksayılan veya erişilemeyen özellik türlerini eklemeyin.

  • Rastgele tür türleri içinde iç içe JsonSerializerContext bildirimleri için destek.

  • Zayıf türdeki kaynak oluşturma senaryolarında derleyici tarafından oluşturulan veya ifade edilemeyen türler için destek. Derleyici tarafından oluşturulan türler kaynak oluşturucu tarafından açıkça belirlenemediği için, System.Text.Json çalışma zamanında en yakın üst öğe çözümlemesi yapar. Bu çözümleme, değerin seri hale getirildiği en uygun üst türü belirler.

  • Yeni dönüştürücü türü JsonStringEnumConverter<TEnum>. Mevcut JsonStringEnumConverter sınıf Yerel AOT'de desteklenmez. Enum türlerinizi aşağıdaki gibi tanımlayabilirsiniz:

    [JsonConverter(typeof(JsonStringEnumConverter<MyEnum>))]
    public enum MyEnum { Value1, Value2, Value3 }
    
    [JsonSerializable(typeof(MyEnum))]
    public partial class MyContext : JsonSerializerContext { }
    

    Daha fazla bilgi için Sabit listesi alanlarını dize olarak serileştirme başlıklı bölüme bakın.

  • Yeni JsonConverter.Type özellik, genel JsonConverter olmayan bir örneğin türünü aramanızı sağlar:

    Dictionary<Type, JsonConverter> CreateDictionary(IEnumerable<JsonConverter> converters)
        => converters.Where(converter => converter.Type != null)
                     .ToDictionary(converter => converter.Type!);
    

    Özellik, null örnekler için JsonConverterFactory ve typeof(T) örnekler için JsonConverter<T> döndürdüğünden null atanabilir.

Zincir kaynağı oluşturucuları

JsonSerializerOptions sınıfı, mevcut TypeInfoResolverChain özelliğini tamamlayan yeni bir TypeInfoResolver özelliği içerir. Bu özellikler, kaynak oluşturucuları zincirleme için sözleşme özelleştirmesinde kullanılır. Yeni özelliğin eklenmesi, tüm zincirlenmiş bileşenleri tek bir çağrı sitesinde belirtmeniz gerekmeyecek anlamına gelir; bunlar olgudan sonra eklenebilir. TypeInfoResolverChain ayrıca zinciri incelemenizi veya bileşenleri kaldırmanızı sağlar. Daha fazla bilgi için bkz. Kaynak oluşturucuları birleştirme.

Buna ek olarak, JsonSerializerOptions.AddContext<TContext>() artık kullanım dışıdır. TypeInfoResolver ve TypeInfoResolverChain özellikleriyle değiştirildi. Daha fazla bilgi için bkz. SYSLIB0049.

Arabirim hiyerarşileri

.NET 8, arabirim hiyerarşilerinden özellikleri seri hale getirme desteği ekler.

Aşağıdaki kod, hem hemen uygulanan arabirimden hem de temel arabiriminden özelliklerin seri hale getirildiği bir örneği gösterir.

public static void InterfaceHierarchies()
{
    IDerived value = new DerivedImplement { Base = 0, Derived = 1 };
    string json = JsonSerializer.Serialize(value);
    Console.WriteLine(json); // {"Derived":1,"Base":0}
}

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; }
}

Adlandırma ilkeleri

JsonNamingPolicy, snake_case (alt çizgi ile) ve kebab-case (kısa çizgi ile) özellik adı dönüştürmeleri için yeni adlandırma ilkeleri içerir. Bu ilkeleri mevcut JsonNamingPolicy.CamelCase ilkeye benzer şekilde kullanın:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
JsonSerializer.Serialize(new { PropertyName = "value" }, options);
// { "property_name" : "value" }

Daha fazla bilgi için bkz. Yerleşik adlandırma ilkesi kullanma.

Salt okunur özellikler

Artık erişimcisi olmayan salt okunur alanlara veya özelliklere deserileştirme yapabilirsiniz.

Bu desteği küresel olarak etkinleştirmek için yeni bir seçenek olan PreferredObjectCreationHandling'yi JsonObjectCreationHandling.Populate olarak ayarlayın. Uyumluluk önemliyse, özniteliğini özellikleri doldurulacak belirli türlere veya tek tek özelliklere yerleştirerek [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)] işlevselliği daha ayrıntılı bir şekilde etkinleştirebilirsiniz.

Örneğin, iki salt okunur özelliğe sahip bir CustomerInfo türe deserializasyon yapan aşağıdaki kodu göz önünde bulundurun.

public static void ReadOnlyProperties()
{
    CustomerInfo customer = JsonSerializer.Deserialize<CustomerInfo>("""
        { "Names":["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 List<string> Names { get; } = new();
    public CompanyInfo Company { get; } = new()
    {
        Name = "N/A",
        PhoneNumber = "N/A"
    };
}

.NET 8'in öncesinde giriş değerleri yoksayılıyor ve Names ve Company özellikleri varsayılan değerlerini koruyordu.

{"Names":[],"Company":{"Name":"N/A","PhoneNumber":"N/A"}}

Artık seri durumdan çıkarma sırasında giriş değerleri, salt okunur özellikleri doldurmak için kullanılır.

{"Names":["John Doe"],"Company":{"Name":"Contoso","PhoneNumber":"N/A"}}

Seri durumdan çıkarma davranışını nasıl dolduracağınıza dair daha fazla bilgi için bkz. Başlatılan özelliklerin doldurulması.

Yansıma tabanlı varsayılanı devre dışı bırakma

Artık yansıma tabanlı seri hale getiriciyi varsayılan olarak devre dışı bırakabilirsiniz. Bu devre dışı bırakma özelliği, özellikle kırpılmış ve Yerel AOT uygulamalarında kullanılmamış yansıma bileşenlerinin yanlışlıkla köklenmesinden kaçınmak için kullanışlıdır. Varsayılan yansıma tabanlı serileştirmeyi devre dışı bırakmak için, bir JsonSerializerOptions bağımsız değişkenin serileştirme ve seri durumdan çıkarma yöntemlerine geçirilmesini gerektirerek, proje dosyanızda JsonSerializer MSBuild özelliğini JsonSerializerIsReflectionEnabledByDefault olarak ayarlayın.

Özellik anahtarının değerini denetlemek için yeni IsReflectionEnabledByDefault API'yi kullanın. Üzerinde System.Text.Json bir kitaplık yazarıysanız, yansıma bileşenlerini yanlışlıkla başlatmadan varsayılan ayarlarınızı yapılandırmak için özelliğine güvenebilirsiniz.

Daha fazla bilgi için bkz. Yansıma varsayılanlarını devre dışı bırakma.

Yeni JsonNode API yöntemleri

JsonNode ve System.Text.Json.Nodes.JsonArray türleri aşağıdaki yeni yöntemleri içerir.

public partial class JsonNode
{
    // Creates a deep clone of the current node and all its descendants.
    public JsonNode DeepClone();

    // Returns true if the two nodes are equivalent JSON representations.
    public static bool DeepEquals(JsonNode? node1, JsonNode? node2);

    // Determines the JsonValueKind of the current node.
    public JsonValueKind GetValueKind(JsonSerializerOptions options = null);

    // If node is the value of a property in the parent
    // object, returns its name.
    // Throws InvalidOperationException otherwise.
    public string GetPropertyName();

    // If node is the element of a parent JsonArray,
    // returns its index.
    // Throws InvalidOperationException otherwise.
    public int GetElementIndex();

    // Replaces this instance with a new value,
    // updating the parent object/array accordingly.
    public void ReplaceWith<T>(T value);

    // Asynchronously parses a stream as UTF-8 encoded data
    // representing a single JSON value into a JsonNode.
    public static Task<JsonNode?> ParseAsync(
        Stream utf8Json,
        JsonNodeOptions? nodeOptions = null,
        JsonDocumentOptions documentOptions = default,
        CancellationToken cancellationToken = default);
}

public partial class JsonArray
{
    // Returns an IEnumerable<T> view of the current array.
    public IEnumerable<T> GetValues<T>();
}

Genel olmayan üyeler

JsonIncludeAttribute ve JsonConstructorAttribute öznitelik açıklamalarını kullanarak belirli bir tür için serileştirme sözleşmesine özel üyeleri katabilirsiniz.

public static void NonPublicMembers()
{
    string json = JsonSerializer.Serialize(new MyPoco(42));
    Console.WriteLine(json);
    // {"X":42}

    JsonSerializer.Deserialize<MyPoco>(json);
}

public class MyPoco
{
    [JsonConstructor]
    internal MyPoco(int x) => X = x;

    [JsonInclude]
    internal int X { get; }
}

Daha fazla bilgi için bkz. Değiştirilemez türleri ve genel olmayan üyeleri ve erişimcileri kullanma.

Akış tabanlı seri durumdan çıkarma API'leri

.NET 8, örneğin IAsyncEnumerable<T>yeni GetFromJsonAsAsyncEnumerable akış seri durumdan çıkarma uzantısı yöntemlerini içerir. Benzer yöntemler, örneğin Task<TResult> döndüren HttpClientJsonExtensions.GetFromJsonAsync, mevcut. Yeni uzantı yöntemleri akış API'lerini çağırır ve döndürür IAsyncEnumerable<T>.

Aşağıdaki kod, yeni uzantı yöntemlerini nasıl kullanabileceğinizi gösterir.

public async static void StreamingDeserialization()
{
    const string RequestUri = "https://api.contoso.com/books";
    using var client = new HttpClient();
    IAsyncEnumerable<Book?> books = client.GetFromJsonAsAsyncEnumerable<Book>(RequestUri);

    await foreach (Book? book in books)
    {
        Console.WriteLine($"Read book '{book?.title}'");
    }
}

public record Book(int id, string title, string author, int publishedYear);

WithAddedModifier uzantısı yöntemi

Yeni WithAddedModifier(IJsonTypeInfoResolver, Action<JsonTypeInfo>) uzantı yöntemi, rastgele IJsonTypeInfoResolver örneklerin serileştirme sözleşmelerinde kolayca değişiklikler yapmanıza olanak tanır.

var options = new JsonSerializerOptions
{
    TypeInfoResolver = MyContext.Default
        .WithAddedModifier(static typeInfo =>
        {
            foreach (JsonPropertyInfo prop in typeInfo.Properties)
            {
                prop.Name = prop.Name.ToUpperInvariant();
            }
        })
};

Yeni JsonContent.Create aşırı yüklemeleri

Artık JsonContent örnekleri kırpma güvenliği veya kaynak tarafından oluşturulan sözleşmeleri kullanarak oluşturabilirsiniz. Yeni yöntemler şunlardır:

var book = new Book(id: 42, "Title", "Author", publishedYear: 2023);
HttpContent content = JsonContent.Create(book, MyContext.Default.Book);

public record Book(int id, string title, string author, int publishedYear);

[JsonSerializable(typeof(Book))]
public partial class MyContext : JsonSerializerContext
{
}

JsonSerializerOptions örneğini dondurma

Aşağıdaki yeni yöntemler bir JsonSerializerOptions örneğin ne zaman dondurulduğunda denetlemenizi sağlar:

  • JsonSerializerOptions.MakeReadOnly()

    Bu aşırı yükleme, kırpma güvenli olacak şekilde tasarlanmıştır ve bu nedenle seçenekler örneğinin bir çözümleyiciyle yapılandırılmadığı durumlarda bir istisna oluşturur.

  • JsonSerializerOptions.MakeReadOnly(Boolean)

    Eğer true bu aşırı yüklemeyi kullanırsanız, bir seçenek eksiği varsa, seçenekler örneğini varsayılan yansıma çözümleyicisiyle doldurur. Bu yöntem RequiresUnreferenceCode/RequiresDynamicCode olarak işaretlenmiştir ve bu nedenle Yerel AOT uygulamaları için uygun değildir.

Yeni IsReadOnly özelliği, seçenekler örneğinin dondurulup dondurulmadığını kontrol etmenize olanak tanır.

Zaman soyutlaması

Yeni TimeProvider sınıf ve ITimer arabirim, test senaryolarında zamanı simüle etmenizi sağlayan zaman soyutlama işlevselliği ekler. Buna ek olarak, Task ve Task.Delay kullanarak zaman ilerlemesine dayanan işlemleri sahte olarak gerçekleştirmek için zaman soyutlamasını kullanabilirsiniz. Zaman soyutlaması aşağıdaki temel zaman işlemlerini destekler:

  • Yerel ve UTC saatini alma
  • Performansı ölçmek için zaman damgası alma
  • Zamanlayıcı oluşturma

Aşağıdaki kod parçacığında bazı kullanım örnekleri gösterilmektedir.

// Get system time.
DateTimeOffset utcNow = TimeProvider.System.GetUtcNow();
DateTimeOffset localNow = TimeProvider.System.GetLocalNow();

TimerCallback callback = s => ((State)s!).Signal();

// Create a timer using the time provider.
ITimer timer = _timeProvider.CreateTimer(
    callback, null, TimeSpan.Zero, Timeout.InfiniteTimeSpan);

// Measure a period using the system time provider.
long providerTimestamp1 = TimeProvider.System.GetTimestamp();
long providerTimestamp2 = TimeProvider.System.GetTimestamp();

TimeSpan period = _timeProvider.GetElapsedTime(providerTimestamp1, providerTimestamp2);
// Create a time provider that works with a
// time zone that's different than the local time zone.
private class ZonedTimeProvider(TimeZoneInfo zoneInfo) : TimeProvider()
{
    private readonly TimeZoneInfo _zoneInfo = zoneInfo ?? TimeZoneInfo.Local;

    public override TimeZoneInfo LocalTimeZone => _zoneInfo;

    public static TimeProvider FromLocalTimeZone(TimeZoneInfo zoneInfo) =>
        new ZonedTimeProvider(zoneInfo);
}

UTF8 geliştirmeleri

Türünüzün hedef aralık alanına dize benzeri bir gösterimini yazmayı etkinleştirmek istiyorsanız, türünüzde yeni IUtf8SpanFormattable arayüzünü uygulayın. Bu yeni arabirim ile yakından ilişkilidir ISpanFormattable, ancak UTF16 ve Span<byte> yerine UTF8'i Span<char>hedefler.

IUtf8SpanFormattable, temel türlerin (ve diğerlerinin) tümünde, string, Span<char> veya Span<byte> hedeflendiğinde tamamen aynı paylaşılan mantıkla uygulanmıştır. Tüm biçimler (yeni "B" ikili tanımlayıcısı dahil) ve tüm kültürler için tam desteğe sahiptir. Bu, artık Byte, Complex, Char, DateOnly, DateTime, DateTimeOffset, Decimal, Double, Guid, Half, IPAddress, IPNetwork, Int16, Int32, Int64, Int128, IntPtr, NFloat, SByte, Single, Rune, TimeOnly, TimeSpan, UInt16, UInt32, UInt64, UInt128, UIntPtr, ve Version kaynaklarından doğrudan UTF-8'e biçimlendirebileceğiniz anlamına gelir.

Yeni Utf8.TryWrite yöntemler, UTF16 tabanlı mevcut MemoryExtensions.TryWrite yöntemlere UTF8 tabanlı bir karşılık sağlar. Karmaşık bir ifadeyi doğrudan UTF8 bayt aralığına biçimlendirmek için ilişkilendirilmiş dize söz dizimini kullanabilirsiniz, örneğin:

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);

Uygulama, IUtf8SpanFormattable üzerindeki biçim değerlerini tanır ve bunların uygulamalarını kullanarak UTF8 gösterimlerini doğrudan hedef dizisine yazar.

Uygulama ayrıca yeni yöntemi de kullanır Encoding.TryGetBytes(ReadOnlySpan<Char>, Span<Byte>, Int32) . Bu yöntem, karşılık geleniyle Encoding.TryGetChars(ReadOnlySpan<Byte>, Span<Char>, Int32) birlikte bir hedef yayılma alanına kodlamayı ve kod çözmeyi destekler. Span, sonuçta elde edilen durumu tutacak kadar uzun değilse, yöntemler bir özel durum atmak yerine false geri döner.

Rastgele çalışma yöntemleri

System.Random ve System.Security.Cryptography.RandomNumberGenerator türleri, rastgelelik ile çalışmak için iki yeni yöntem sağlar.

GetItems<T>()

Yeni System.Random.GetItems ve System.Security.Cryptography.RandomNumberGenerator.GetItems yöntemleri, bir giriş kümesinden belirli sayıda öğeyi rastgele seçmenize olanak sağlar. Aşağıdaki örnek, System.Random.GetItems<T>() özelliği tarafından sağlanan örnek üzerinde Random.Shared kullanarak bir diziye rastgele 31 öğe eklemenin nasıl yapıldığını göstermektedir. Bu örnek, oyuncuların renkli düğme dizisini hatırlaması gereken bir "Simon" oyununda kullanılabilir.

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 ...

<Karıştır>()

Yeni Random.Shuffle ve RandomNumberGenerator.Shuffle<T>(Span<T>) yöntemleri, bir yayılma alanının sırasını rastgele oluşturmanıza olanak sağlar. Bu yöntemler makine öğrenmesindeki eğitim yanlılığını azaltmak için kullanışlıdır (dolayısıyla ilk şey her zaman eğitim değildir ve son şey her zaman test edilir).

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);
// ...

Performans odaklı türler

.NET 8, uygulama performansını artırmayı amaçlayan çeşitli yeni türler sağlar.

  • Yeni System.Collections.Frozen ad alanı koleksiyon türlerini FrozenDictionary<TKey,TValue> ve FrozenSet<T>içerir. Bu türler, koleksiyon oluşturulduktan sonra anahtarlarda ve değerlerde herhangi bir değişikliğe izin vermez. Bu gereksinim daha hızlı okuma işlemlerine olanak tanır (örneğin, TryGetValue()). Bu türler özellikle ilk kullanımda doldurulan ve daha sonra uzun süreli bir hizmet süresi boyunca kalıcı hale gelen koleksiyonlar için kullanışlıdır, örneğin:

    private static readonly FrozenDictionary<string, bool> s_configurationData =
        LoadConfigurationData().ToFrozenDictionary();
    
    // ...
    if (s_configurationData.TryGetValue(key, out bool setting) && setting)
    {
        Process();
    }
    
  • MemoryExtensions.IndexOfAny gibi yöntemler geçirilen koleksiyondaki herhangi bir değerin ilk oluşumunu arar. Yeni System.Buffers.SearchValues<T> tür, bu tür yöntemlere geçirilecek şekilde tasarlanmıştır. .NET 8, yeni türün bir örneğini kabul eden MemoryExtensions.IndexOfAny gibi yöntemlerin yeni aşırı yüklemelerini ekler. örneğini SearchValues<T>oluşturduğunuzda, sonraki aramaları iyileştirmek için gerekli olan tüm veriler o anda türetilir ve bu da işin önden yapıldığı anlamına gelir. (Türü SearchValues<T> .NET 9'da genişletildi. Daha fazla bilgi için bkz SearchValues . genişletme.)

  • Yeni System.Text.CompositeFormat tür, derleme zamanında bilinmeyen biçim dizelerini iyileştirmek için kullanışlıdır (örneğin, biçim dizesi bir kaynak dosyasından yüklenirse). Dizeyi ayrıştırma gibi işleri yapmak için başında biraz daha fazla zaman harcanır, ancak bu şekilde her kullanımda aynı işi yapmaktan kurtulunur.

    private static readonly CompositeFormat s_rangeMessage =
        CompositeFormat.Parse(LoadRangeMessageResource());
    
    // ...
    static string GetMessage(int min, int max) =>
        string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max);
    
  • Yeni System.IO.Hashing.XxHash3 ve System.IO.Hashing.XxHash128 türleri hızlı XXH3 ve XXH128 karma algoritmalarının uygulamalarını sağlar.

System.Numerics ve System.Runtime.Intrinsics

Bu bölümde System.Numerics ve System.Runtime.Intrinsics ad alanlarındaki iyileştirmeler ele alınmaktadır.

  • Vector256<T>, Matrix3x2ve Matrix4x4 .NET 8'de donanım hızlandırmayı geliştirdi. Örneğin, Vector256<T> mümkün olduğunca 2x Vector128<T> işlemler olacak şekilde dahili olarak yeniden uygulandı. Bu, örneğin Arm64'te olduğu gibi, Vector128.IsHardwareAccelerated == trueancakVector256.IsHardwareAccelerated == false bazı işlevlerin kısmi hızlandırılmasına olanak tanır.
  • Donanım içi işlevler artık ConstExpected özniteliğiyle işaretlenmiştir. Bu, kullanıcıların temel donanım sabit beklediğinde ve bu nedenle sabit olmayan bir değerin beklenmedik bir şekilde performansa zarar verebileceğinin farkında olmasını sağlar.
  • Lerp(TSelf, TSelf, TSelf) Lerp API, IFloatingPointIeee754<TSelf> ve dolayısıyla float (Single), double (Double) ve Half öğelerine eklendi. Bu API, iki değer arasındaki doğrusal ilişkilendirmenin verimli ve doğru bir şekilde gerçekleştirilmesini sağlar.

Vector512 ve AVX-512

.NET Core 3.0, x86/x64 için platforma özgü donanımsal özel API'leri kapsayan SIMD desteğini genişletmiştir. .NET 5, Arm64 için destek ekledi ve .NET 7, platformlar arası donanım iç bilgilerini ekledi. .NET 8, Vector512<T> ve Intel Advanced Vector Extensions 512 (AVX-512) yönergelerini destekleyerek SIMD desteğini geliştirir.

Özel olarak, .NET 8, AVX-512'nin aşağıdaki temel özellikleri için destek içerir:

  • 512 bit vektör işlemleri
  • Ek 16 SIMD yazmaç
  • 128 bit, 256 bit ve 512 bit vektörler için ek yönergeler sağlanabilir

İşlevselliği destekleyen bir donanımınız varsa, Vector512.IsHardwareAccelerated şimdi bildirir true.

.NET 8 ayrıca ad alanının altına platforma System.Runtime.Intrinsics.X86 özgü birkaç sınıf ekler:

Bu sınıflar, yalnızca 64 bit'lik işlemler için kullanılabilen yönergeler için bir IsSupported özelliği ve bir iç içe Avx512F.X64 sınıfı sunmaları nedeniyle diğer yönerge seti mimarileri (ISA) ile aynı genel şekli izler. Ayrıca, her sınıfın ilgili yönerge kümesi için vektör uzunluğu uzantılarını ortaya koyan iç içe bir sınıfı daha vardır.

Kodunuzda açıkça Vector512'a özgü veya Avx512F'e özgü yönergeleri kullanmasanız bile, muhtemelen yeni AVX-512 desteğinden yararlanmaya devam edersiniz. JIT, Vector128<T> veya Vector256<T> kullanırken ek yazmaçlardan ve yönergelerden örtük olarak yararlanabilir. Temel sınıf kitaplığı, ilkel türler için kullanıma sunulan matematik API'lerinin çoğunda ve Span<T> tarafından ReadOnlySpan<T> kullanıma sunulan çoğu işlemde bu donanım iç öğelerini dahili olarak kullanır.

Veri doğrulama

System.ComponentModel.DataAnnotations ad alanı, bulutta yerel hizmetlerin doğrulama senaryolarına yönelik yeni veri doğrulama öznitelikleri içermektedir. Önceden var olan DataAnnotations doğrulayıcılar, form üzerindeki alanlar gibi tipik UI veri girişi doğrulamasına yönelik olsa da, yeni öznitelikler yapılandırma seçenekleri gibi kullanıcı girişi olmayan verileri doğrulamak için tasarlanmıştır. Yeni özniteliklere ek olarak, türüne RangeAttribute yeni özellikler eklendi.

Yeni API Description
RangeAttribute.MinimumIsExclusive
RangeAttribute.MaximumIsExclusive
sınırların izin verilen aralığa dahil edilip edilmeyeceğini belirtir.
System.ComponentModel.DataAnnotations.LengthAttribute Dizeler veya koleksiyonlar için hem alt hem de üst sınırları belirtir. Örneğin, [Length(10, 20)] bir koleksiyonda en az 10 öğe ve en fazla 20 öğe gerektirir.
System.ComponentModel.DataAnnotations.Base64StringAttribute Bir dizenin geçerli bir Base64 gösterimi olduğunu doğrular.
System.ComponentModel.DataAnnotations.AllowedValuesAttribute
System.ComponentModel.DataAnnotations.DeniedValuesAttribute
İzin verme listelerini ve reddetme listelerini sırasıyla belirtin. Örneğin, [AllowedValues("apple", "banana", "mango")].

Metrics

Yeni API'ler, Meter ve Instrument nesnelerini oluşturduğunuzda anahtar-değer çifti etiketleri eklemenize olanak sağlar. Yayımlanan ölçüm ölçümlerinin toplayıcıları, toplanan değerleri ayırt etmek için etiketleri kullanabilir.

var options = new MeterOptions("name")
{
    Version = "version",
    // Attach these tags to the created meter.
    Tags = new TagList()
    {
        { "MeterKey1", "MeterValue1" },
        { "MeterKey2", "MeterValue2" }
    }
};

Meter meter = meterFactory!.Create(options);

Counter<int> counterInstrument = meter.CreateCounter<int>(
    "counter", null, null, new TagList() { { "counterKey1", "counterValue1" } }
);
counterInstrument.Add(1);

Yeni API'ler şunlardır:

Cryptography

.NET 8, SHA-3 karma temelleri için destek ekler. (SHA-3 şu anda OpenSSL 1.1.1 veya üzeri ve Windows 11 Derleme 25324 veya sonraki sürümleriyle Linux tarafından desteklenmektedir.) SHA-2'nin kullanılabildiği API'ler artık SHA-3 desteği sunmaktadır. Bu, karma oluşturma için SHA3_256, SHA3_384 ve SHA3_512; HMAC için HMACSHA3_256, HMACSHA3_384 ve HMACSHA3_512; algoritmanın yapılandırılabilir olduğu karma oluşturma için HashAlgorithmName.SHA3_256, HashAlgorithmName.SHA3_384 ve HashAlgorithmName.SHA3_512; ve RSA OAEP şifrelemesi için RSAEncryptionPadding.OaepSHA3_256, RSAEncryptionPadding.OaepSHA3_384 ve RSAEncryptionPadding.OaepSHA3_512 içerir.

Aşağıdaki örnekte, platformun SHA-3'ü desteklenip desteklemediğini belirlemek için özelliği de dahil olmak üzere SHA3_256.IsSupported API'lerin nasıl kullanılacağı gösterilmektedir.

// Hashing example
if (SHA3_256.IsSupported)
{
    byte[] hash = SHA3_256.HashData(dataToHash);
}
else
{
    // ...
}

// Signing example
if (SHA3_256.IsSupported)
{
     using ECDsa ec = ECDsa.Create(ECCurve.NamedCurves.nistP256);
     byte[] signature = ec.SignData(dataToBeSigned, HashAlgorithmName.SHA3_256);
}
else
{
    // ...
}

SHA-3 desteği şu anda şifreleme temel öğelerini desteklemeyi hedeflemektedir. Üst düzey yapıların ve protokollerin başlangıçta SHA-3'i tam olarak desteklemesi beklenmiyor. Bu protokoller X.509 sertifikalarını SignedXmlve COSE'yi içerir.

Ağ Kurma

HTTPS proxy desteği

Şimdiye kadar, tümünü destekleyen HttpClient proxy türleri, HTTPS URI'leri için bile istemcinin hangi siteye bağlandığını görmek için bir "ortadaki adam"a izin verdi. HttpClient artık tüm isteklerin tam gizlilikle işlenebilmesi için istemci ile ara sunucu arasında şifreli bir kanal oluşturan HTTPS proxy'yi destekliyor.

HTTPS ara sunucusunu etkinleştirmek için ortam değişkenini all_proxy ayarlayın veya ara sunucuyu program aracılığıyla denetlemek için sınıfını kullanın WebProxy .

Unix: export all_proxy=https://x.x.x.x:3218 Windows: set all_proxy=https://x.x.x.x:3218

Ara sunucuyu programatik olarak kontrol etmek için WebProxy sınıfını da kullanabilirsiniz.

Akış tabanlı ZipFile yöntemleri

.NET 8, bir dizine dahil edilen tüm dosyaları toplamanıza ve sıkıştırmanıza ve ardından sonuçta elde edilen zip dosyasını sağlanan akışta depolamanıza olanak sağlayan yeni aşırı yüklemeleri ZipFile.CreateFromDirectory içerir. Benzer şekilde, yeni ZipFile.ExtractToDirectory overloadlar sıkıştırılmış dosya içeren bir akışı sağlamanıza ve içeriğini dosya sistemine ayıklamanıza olanak tanır. Yeni aşırı yüklemeler şunlardır:

namespace System.IO.Compression;

public static partial class ZipFile
{
    public static void CreateFromDirectory(
        string sourceDirectoryName, Stream destination);

    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destination,
        CompressionLevel compressionLevel,
        bool includeBaseDirectory);

    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destination,
        CompressionLevel compressionLevel,
        bool includeBaseDirectory,
    Encoding? entryNameEncoding);

    public static void ExtractToDirectory(
        Stream source, string destinationDirectoryName) { }

    public static void ExtractToDirectory(
        Stream source, string destinationDirectoryName, bool overwriteFiles) { }

    public static void ExtractToDirectory(
        Stream source, string destinationDirectoryName, Encoding? entryNameEncoding) { }

    public static void ExtractToDirectory(
        Stream source, string destinationDirectoryName, Encoding? entryNameEncoding, bool overwriteFiles) { }
}

Disk alanı kısıtlandığında bu yeni API'ler yararlı olabilir, çünkü diski ara adım olarak kullanmaktan kaçınırlar.

Uzantı kitaplıkları

Bu bölüm aşağıdaki alt konuları içerir:

Anahtarlı DI hizmetleri

Anahtarlı bağımlılık ekleme (DI) hizmetleri, anahtarları kullanarak DI hizmetlerini kaydetmek ve almak için bir araç sağlar. Anahtarları kullanarak, hizmetleri kaydetme ve kullanma şeklinizi kapsamlayabilirsiniz. Yeni API'lerden bazıları şunlardır:

Aşağıdaki örnekte anahtarlı DI hizmetlerinin nasıl kullanılacağı gösterilmektedir.

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<BigCacheConsumer>();
builder.Services.AddSingleton<SmallCacheConsumer>();
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
WebApplication app = builder.Build();
app.MapGet("/big", (BigCacheConsumer data) => data.GetData());
app.MapGet("/small", (SmallCacheConsumer data) => data.GetData());
app.MapGet("/big-cache", ([FromKeyedServices("big")] ICache cache) => cache.Get("data"));
app.MapGet("/small-cache", (HttpContext httpContext) => httpContext.RequestServices.GetRequiredKeyedService<ICache>("small").Get("data"));
app.Run();

class BigCacheConsumer([FromKeyedServices("big")] ICache cache)
{
    public object? GetData() => cache.Get("data");
}

class SmallCacheConsumer(IServiceProvider serviceProvider)
{
    public object? GetData() => serviceProvider.GetRequiredKeyedService<ICache>("small").Get("data");
}

public interface ICache
{
    object Get(string key);
}

public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

Daha fazla bilgi için bkz. dotnet/runtime#64427.

Barındırılan yaşam döngüsü hizmetleri

Barındırılan hizmetler artık uygulama yaşam döngüsü sırasında yürütme için daha fazla seçeneğe sahiptir. IHostedService ve StartAsync sağlandı, şimdi StopAsync şu ek yöntemleri IHostedLifecycleService sağlıyor:

Bu yöntemler sırasıyla mevcut noktalardan önce ve sonra çalışır.

Aşağıdaki örnekte yeni API'lerin nasıl kullanılacağı gösterilmektedir.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

internal class HostedLifecycleServices
{
    public async static void RunIt()
    {
        IHostBuilder hostBuilder = new HostBuilder();
        hostBuilder.ConfigureServices(services =>
        {
            services.AddHostedService<MyService>();
        });

        using (IHost host = hostBuilder.Build())
        {
            await host.StartAsync();
        }
    }

    public class MyService : IHostedLifecycleService
    {
        public Task StartingAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
        public Task StartAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
        public Task StartedAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
        public Task StopAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
        public Task StoppedAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
        public Task StoppingAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    }
}

Daha fazla bilgi için bkz. dotnet/runtime#86511.

Seçenekler doğrulaması

Kaynak oluşturucu

Başlangıç ek yükünü azaltmak ve doğrulama özellik kümesini geliştirmek için doğrulama mantığını uygulayan bir kaynak kodu oluşturucuyu kullanıma aldık. Aşağıdaki kod örnek modelleri ve doğrulayıcı sınıflarını gösterir.

public class FirstModelNoNamespace
{
    [Required]
    [MinLength(5)]
    public string P1 { get; set; } = string.Empty;

    [Microsoft.Extensions.Options.ValidateObjectMembers(
        typeof(SecondValidatorNoNamespace))]
    public SecondModelNoNamespace? P2 { get; set; }
}

public class SecondModelNoNamespace
{
    [Required]
    [MinLength(5)]
    public string P4 { get; set; } = string.Empty;
}

[OptionsValidator]
public partial class FirstValidatorNoNamespace
    : IValidateOptions<FirstModelNoNamespace>
{
}

[OptionsValidator]
public partial class SecondValidatorNoNamespace
    : IValidateOptions<SecondModelNoNamespace>
{
}

Uygulamanız bağımlılık ekleme kullanıyorsa aşağıdaki örnek kodda gösterildiği gibi doğrulamayı ekleyebilirsiniz.

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<FirstModelNoNamespace>(
    builder.Configuration.GetSection("some string"));

builder.Services.AddSingleton<
    IValidateOptions<FirstModelNoNamespace>, FirstValidatorNoNamespace>();
builder.Services.AddSingleton<
    IValidateOptions<SecondModelNoNamespace>, SecondValidatorNoNamespace>();

ValidateOptionsResultBuilder türü

.NET 8, bir ValidateOptionsResultBuilder türünü bir ValidateOptionsResult nesnesi oluşturmayı kolaylaştırmak için tanıtır. Önemli olan, bu oluşturucu birden çok hatanın birikmesini sağlar. Daha önce, ValidateOptionsResult uygulaması için gereken IValidateOptions<TOptions>.Validate(String, TOptions) nesnesini oluşturmak zordu ve bazen bunun sonucunda katmanlı doğrulama hataları ortaya çıkıyordu. Birden çok hata varsa doğrulama işlemi genellikle ilk hatada durdurulur.

Aşağıdaki kod parçacığında örnek kullanımı gösterilmektedir 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();

LoggerMessageAttribute oluşturucuları

LoggerMessageAttribute artık ek yapılandırıcı aşırı yüklemeler sunar. Daha önce parametresiz oluşturucuyu veya tüm parametreleri (olay kimliği, günlük düzeyi ve ileti) gerektiren oluşturucuyu seçmeniz gerekiyordu. Yeni aşırı yüklemeler, gerekli parametreleri azaltılmış kodla belirtme konusunda daha fazla esneklik sunar. Bir olay kimliği sağlamazsanız sistem otomatik olarak bir olay kimliği oluşturur.

public LoggerMessageAttribute(LogLevel level, string message);
public LoggerMessageAttribute(LogLevel level);
public LoggerMessageAttribute(string message);

Uzantı ölçümleri

IMeterFactory arabirimi

Yeni IMeterFactory arabirimini bağımlılık ekleme (DI) kapsayıcılarına kaydedebilir ve Meter nesnelerini yalıtılmış bir şekilde oluşturmak için kullanabilirsiniz.

IMeterFactory varsayılan ölçüm fabrikası uygulamasını kullanarak öğesini DI kapsayıcısına kaydedin:

// 'services' is the DI IServiceCollection.
services.AddMetrics();

Tüketiciler daha sonra metre fabrikasını edinebilir ve bunu yeni bir Meter nesnesi oluşturmak için kullanabilir.

IMeterFactory meterFactory = serviceProvider.GetRequiredService<IMeterFactory>();

MeterOptions options = new MeterOptions("MeterName")
{
    Version = "version",
};

Meter meter = meterFactory.Create(options);

MetricCollector<T> sınıfı

Yeni MetricCollector<T> sınıf, ölçüm ölçümlerini zaman damgalarıyla birlikte kaydetmenizi sağlar. Buna ek olarak, sınıf, doğru bir zaman damgası oluşturmak için seçtiğiniz bir zaman sağlayıcısını kullanma esnekliği sunar.

const string CounterName = "MyCounter";
DateTimeOffset now = DateTimeOffset.Now;

var timeProvider = new FakeTimeProvider(now);
using var meter = new Meter(Guid.NewGuid().ToString());
Counter<long> counter = meter.CreateCounter<long>(CounterName);
using var collector = new MetricCollector<long>(counter, timeProvider);

Assert.IsNull(collector.LastMeasurement);

counter.Add(3);

// Verify the update was recorded.
Assert.AreEqual(counter, collector.Instrument);
Assert.IsNotNull(collector.LastMeasurement);

Assert.AreSame(collector.GetMeasurementSnapshot().Last(), collector.LastMeasurement);
Assert.AreEqual(3, collector.LastMeasurement.Value);
Assert.AreEqual(now, collector.LastMeasurement.Timestamp);

System.Numerics.Tensors.TensorPrimitives

Güncelleştirilmiş System.Numerics.Tensors NuGet paketi, tensor işlemleri için destek ekleyen yeni System.Numerics.Tensors.TensorPrimitives türdeki API'leri içerir. Tensor ilkelleri, yapay zeka ve makine öğrenmesi gibi yoğun veri kullanan iş yüklerini iyileştirir.

Anlamsal arama ve alma ile artırılmış oluşturma (RAG) gibi yapay zeka iş yükleri, ilgili verilerle istemleri geliştirerek ChatGPT gibi büyük dil modellerinin doğal dil yeteneklerini genişletir. Bu iş yükleri için, bir soruyu yanıtlamak için en uygun verileri bulmak için kosinüs benzerliği gibi vektörlerle ilgili işlemler çok önemlidir. türü vektör TensorPrimitives işlemleri için API'ler sağlar.

Daha fazla bilgi için Duyuru .NET 8 RC 2 blog gönderisine bakın.

Yerel AOT desteği

Yerel AOT olarak yayımlama seçeneği ilk olarak .NET 7'de kullanıma sunulmuştur. Yerel AOT ile uygulama yayımlamak, uygulamanızın çalışma zamanı gerektirmeyen tam olarak bağımsız bir sürümünü oluşturur; her şey tek bir dosyaya eklenir. .NET 8, yerel AOT yayınlamasına aşağıdaki iyileştirmeleri getiriyor.

  • macOS'ta x64 ve Arm64 mimarileri için destek ekler.

  • Linux'ta Yerel AOT uygulamalarının boyutlarını 50%kadar azaltır. Aşağıdaki tabloda, .NET 7 ve .NET 8'de tüm .NET çalışma zamanını içeren Yerel AOT ile yayımlanan "Hello World" uygulamasının boyutu gösterilmektedir:

    İşletim sistemi .NET 7 .NET 8
    Linux x64 (ile -p:StripSymbols=true) 3,76 MB 1,84 MB
    Windows x64 2,85 MB 1,77 MB
  • Bir iyileştirme tercihi belirtmenize olanak tanır: boyut veya hız. Varsayılan olarak, derleyici uygulamanın boyutuna dikkat ederken hızlı kod oluşturmayı seçer. Ancak, MSBuild özelliğini kullanarak özellikle biri veya diğeri için en iyi duruma getirebilirsiniz <OptimizationPreference> . Daha fazla bilgi için bkz. AOT dağıtımlarını iyileştirme.

Yerel AOT ile iOS benzeri platformları hedefleme

.NET 8, iOS benzeri platformlar için Yerel AOT desteğini etkinleştirmek için çalışmaya başlar. Artık aşağıdaki platformlarda Yerel AOT ile .NET iOS ve .NET MAUI uygulamaları derleyebilir ve çalıştırabilirsiniz:

  • ios
  • iossimulator
  • maccatalyst
  • tvos
  • tvossimulator

Ön test, Mono yerine Yerel AOT kullanan .NET iOS uygulamaları için disk üzerindeki uygulama boyutunun yaklaşık 35% azaldığını gösterir. .NET MAUI iOS uygulamaları için diskte uygulama boyutu 50%kadar azalır. Ayrıca, başlangıç süresi de daha hızlıdır. .NET iOS uygulamaları yaklaşık 28% daha hızlı başlangıç süresine sahipken.NET MAUI iOS uygulamaları Mono ile karşılaştırıldığında yaklaşık 50% daha iyi başlangıç performansına sahiptir. .NET 8 desteği deneyseldir ve bir bütün olarak özellik için yalnızca ilk adımdır. Daha fazla bilgi için .NET MAUI'de .NET 8 Performans Geliştirmeleri blog gönderisine bakın.

Yerel AOT desteği, uygulama dağıtımına yönelik bir katılım özelliği olarak kullanılabilir; Mono hala uygulama geliştirme ve dağıtım için varsayılan çalışma zamanıdır. tr-TR: Yerel AOT ile bir iOS cihazında .NET MAUI uygulaması derlemek ve çalıştırmak için dotnet workload install maui kullanarak .NET MAUI iş yükünü yükleyin ve dotnet new maui -n HelloMaui kullanarak uygulamayı oluşturun. Ardından proje dosyasında MSBuild özelliğini PublishAot olarak true ayarlayın.

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Gerekli özelliği ayarladığınızda ve aşağıdaki örnekte gösterildiği gibi çalıştırdığınızda dotnet publish , uygulama Yerel AOT kullanılarak dağıtılır.

dotnet publish -f net8.0-ios -c Release -r ios-arm64  /t:Run

Sınırlamalar

Tüm iOS özellikleri Yerel AOT ile uyumlu değildir. Benzer şekilde, iOS'ta yaygın olarak kullanılan tüm kitaplıklar NativeAOT ile uyumlu değildir. Yerel AOT dağıtımının mevcut sınırlamalarına ek olarak, aşağıdaki listede iOS benzeri platformları hedeflerken diğer sınırlamalardan bazıları gösterilmektedir:

  • Yerel AOT'nin kullanılması yalnızca uygulama dağıtımı (dotnet publish) sırasında etkinleştirilir.
  • Yönetilen kod hata ayıklama yalnızca Mono ile desteklenir.
  • .NET MAUI çerçevesiyle uyumluluk sınırlıdır.

Android uygulamaları için AOT derlemesi

Uygulama boyutunu küçültmek için, Android'i hedefleyen .NET ve .NET MAUI uygulamaları, Yayın modunda oluşturulduklarında önceden profili oluşturulan (AOT) derleme modunu kullanır. Profili oluşturulan AOT derlemesi, normal AOT derlemesine göre daha az yöntemi etkiler. .NET 8, uygulama boyutunu daha da küçültmek için Android uygulamaları için daha fazla AOT derlemesini etkinleştirmenizi sağlayan bir özelliği <AndroidStripILAfterAOT> sunar.

<PropertyGroup>
  <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
</PropertyGroup>

Varsayılan olarak, AndroidStripILAfterAOT'i true olarak ayarlamak, AndroidEnableProfiledAot varsayılan ayarını geçersiz kılar ve AOT ile derlenmiş olan (neredeyse) tüm yöntemlerin kırpılmasına izin verir. Ayrıca, her iki özelliği de açıkça olarak ayarlayarak profilli AOT ve IL çıkarmayı birlikte kullanabilirsiniz:

<PropertyGroup>
  <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT>
  <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>

Çapraz yerleşik Windows uygulamaları

Windows dışı platformlarda Windows'ı hedefleyen uygulamalar oluşturduğunuzda, sonuçta elde edilen yürütülebilir dosya artık belirtilen Win32 kaynaklarıyla (uygulama simgesi, bildirim, sürüm bilgileri gibi) güncelleştirilir.

Daha önce, bu tür kaynaklara sahip olmak için uygulamaların Windows üzerinde derlenmesi gerekiyordu. Hem altyapı karmaşıklığını hem de kaynak kullanımını etkileyen önemli bir sorun noktası olduğundan, binalar arası destekteki bu boşluğun düzeltilmesi popüler bir istekti.

Ayrıca bakınız