net8

前言

官网是最好的老师,跟着慢慢学,顺便做下笔记就是自己的了。

net8新增功能:https://learn.microsoft.com/zh-cn/dotnet/core/whats-new/dotnet-8

1.安装使用Net8

面临的第一个问题,如何使用net8预览版?

1.1安装

地址:https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0

根据自己的需要下载对应的版本,我的环境是windows x64

image-20231108233209262

下载完成后安装

image-20231108233342599

检查命令

dotnet --list-sdks

image-20231108233431191

1.2VS2022配置

安装完成后vs2022并没有net8环境

工具--->管理和预览(p)功能

image-20231108233549040

使用.NET SDK预览版

image-20231108233654256

重启之后新建项目

image-20231108233805664

2.支持Half、Int128UInt128、序列化

代码

// [65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]
Console.WriteLine(JsonSerializer.Serialize(new object[] { Half.MaxValue, Int128.MaxValue, UInt128.MaxValue }));

如图

image-20231108234646856

3.源生成器

配置类

public class WeatherForecast
{
    public required DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}
string jsonstr = """
{
"Date":"2023-11-09T00:00:00",
"TemperatureCelsius":25,
"Summary":"Hot"
}
""";

WeatherForecast? weatherForecast;

3.1JsonTypeInfo

weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonstr, SourceGenerationContext.Default.WeatherForecast);
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine(jsonstr);

3.2JsonSerializerContext

weatherForecast = JsonSerializer.Deserialize(jsonstr, typeof(WeatherForecast), SourceGenerationContext.Default) as WeatherForecast;
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine(jsonstr);

3.3JsonSerializerOptions


var sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = JsonTypeInfoResolver.Combine(SourceGenerationContext.Default),
    WriteIndented = true,
};
weatherForecast = JsonSerializer.Deserialize(jsonstr, typeof(WeatherForecast), sourceGenOptions) as WeatherForecast;
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine(jsonstr);

3.4枚举序列化为字符串

配置类

public class WeatherForecastWithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation Precipitation { get; set; }
}

// 打印枚举的文本
// 注释掉打印枚举的值
[JsonConverter(typeof(JsonStringEnumConverter<Precipitation>))]
public enum Precipitation
{
    Drizzle, Rain, Sleet, Hail, Snow
}


[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class WeatherForecastWithPrecipEnumContext : JsonSerializerContext { }
var weatherForecastWithPrecipEnum = new WeatherForecastWithPrecipEnum
{
    Date = DateTime.Parse("2023-11-09"),
    TemperatureCelsius = 26,
    Precipitation = Precipitation.Sleet
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    TypeInfoResolver = WeatherForecastWithPrecipEnumContext.Default
};

string? jsonstr1 = JsonSerializer.Serialize(weatherForecastWithPrecipEnum, options);
Console.WriteLine(jsonstr1);

4.接口层次结构

.NET 8 添加了对从接口层次结构序列化属性的支持。

image-20231109003912393

IDerived value1 = new DerivedImplement { Base = 0, Derived = 1 };
IBase value2 = value1;
Console.WriteLine(JsonSerializer.Serialize(value1)); // {"Base":0,"Derived":1}
Console.WriteLine(JsonSerializer.Serialize(value2)); // {"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; }
}

5.命名策略

支持下划线和中划线(“_”和“-”);

var options = new JsonSerializerOptions
{
    // 小写下划线
    // {"property_name":"value"}
    // PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower

    // 大写下划线
    // {"PROPERTY_NAME":"value"}
    // PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper

    // 小写中划线
    // {"property-name":"value"}
    // PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower

    // 大写中划线
    // {"PROPERTY-NAME":"value"}
    // PropertyNamingPolicy = JsonNamingPolicy.KebabCaseUpper

    // 驼峰
    // {"propertyName":"value"}
    // PropertyNamingPolicy = JsonNamingPolicy.CamelCase

    // 默认
    // {"PropertyName":"value"}
};

Console.WriteLine(JsonSerializer.Serialize(new { PropertyName = "value" }, options));

6.只读属性反序列化

现在可以反序列化到只读字段或属性(即没有 set 访问器的字段或属性)。

请将新选项 [PreferredObjectCreationHandling]设置为 [JsonObjectCreationHandling.Populate]。

class CompanyInfo
{
    public required string Name { get; set; }
    public string? PhoneNumber { get; set; }
}

[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class CustomerInfo
{

    public List<string> Names { get; } = new();
    public CompanyInfo Company { get; } = new() { Name = "N/A", PhoneNumber = "N/A" };
}

实现:


CustomerInfo customer = JsonSerializer.Deserialize<CustomerInfo>(
"""
{
  "Names":["John Doe"],
  "Company":{
    "Name":"Contoso",
    "PhoneNumber":"123456"
  }
}
"""
)!;
Console.WriteLine(JsonSerializer.Serialize(customer, new JsonSerializerOptions
{
    WriteIndented = true,
    PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate
}));

7.禁用基于反射的默认值

若要通过要求将 [JsonSerializerOptions] 参数传递给 [JsonSerializer]序列化和反序列化方法来禁用默认的基于反射的序列化,请在项目文件中将 JsonSerializerIsReflectionEnabledByDefault MSBuild 属性设置为 false

image-20231109213752963

如果程序设置JsonSerializerIsReflectionEnabledByDefault为false,还可通过代码TypeInfoResolver配置

image-20231109213841873

代码如下:

object obj = new object[] { Half.MaxValue, Int128.MaxValue, UInt128.MaxValue };
//[65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]
Console.WriteLine(JsonSerializer.Serialize(obj,GetDefaultOptions()));
//"AQID"
Console.WriteLine(JsonSerializer.Serialize<ReadOnlyMemory<byte>>(new byte[] { 1, 2, 3 }, GetDefaultOptions()));
//[1, 2, 3]
Console.WriteLine(JsonSerializer.Serialize<Memory<int>>(new int[] { 1, 2, 3 }, GetDefaultOptions()));


static JsonSerializerOptions GetDefaultOptions()
{
    if (JsonSerializer.IsReflectionEnabledByDefault)
    {
        return new()
        {
            TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
            PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower
        };
    }
    return new()
    {
        TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
        PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower
    };
}

8.JsonNode与JsonArray新增方法

代码如下:


string jsonString = """
{
   "Names":["John Doe","Li Li"],
   "Company":{
      "Name":"Contoso"
   }
}
""";

var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// 将Stream作为UTF-8编码数据(表示单个JSON值)分析为JsonNode。流会被完整读取。
var jsonNode1 = await JsonNode.ParseAsync(stream);
// 创建JsonNode类的新实例。以递归方式克隆所有子节点。
var jsonNode2 = jsonNode1!.DeepClone();
Console.WriteLine(jsonNode1);
// 比较俩个节点的值,包括所有子节点的值。
Console.WriteLine(JsonNode.DeepEquals(jsonNode1, jsonNode2));
jsonNode2!["Company"]!["Name"] = "Peng";
Console.WriteLine(jsonNode2);
Console.WriteLine(JsonNode.DeepEquals(jsonNode1, jsonNode2));
// 从父对象返回当前节点的属性名称。
Console.WriteLine(jsonNode1!["Company"]!["Name"]!.GetPropertyName());
// 从父JsonArrary级返回当前节点的索引。
Console.WriteLine(jsonNode1!["Names"]![1]!.GetElementIndex());

9.非公共成员

可以使用 JsonIncludeAttributeJsonConstructorAttribute 特性注释将非公共成员加入到给定类型的序列化协定中。

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

var myPoco = JsonSerializer.Deserialize<MyPoco>(json);
Console.WriteLine(myPoco?.X);

Console.WriteLine("Hello, World!");
Console.Read();

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

    [JsonInclude]
    internal int X { get; }
}

10.流式反序列化

GetFromJsonAsAsyncEnumerable。 新的扩展方法会调用流式处理 API 并返回 [IAsyncEnumerable]。

const string RequestUri = "http://localhost:5000/WeatherForecast";
using var client = new HttpClient();
var weathers = client.GetFromJsonAsAsyncEnumerable<Weather>(RequestUri);
await foreach (var weather in weathers)
{
    Console.WriteLine($"Weather Date:{weather?.date} '{weather?.summary}'");
}

Console.WriteLine("-----------------");

var stream = await client.GetStreamAsync(RequestUri);
weathers = JsonSerializer.DeserializeAsyncEnumerable<Weather>(stream);
await foreach (var weather in weathers)
{
    Console.WriteLine($"Weather Date:{weather?.date} '{weather?.summary}'");
}

自己新建一个WebAPI运行访问即可

image-20231109223536143

11.WithAddedModifier扩展方法

可以轻松地对任意 IJsonTypeInfoResolver 实例的序列化协定进行修改。

WeatherForecast? weather = new WeatherForecast()
{
    Date = DateTime.Now,
    TemperatureCelsius = 26,
    Summary = "Hot"
};

var options = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default.WithAddedModifier(static typeInfo =>
    {
        foreach (JsonPropertyInfo prop in typeInfo.Properties)
        {
            prop.Name = prop.Name.ToUpperInvariant() + "---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }
    }),
    WriteIndented = true
};
var jsonStr = JsonSerializer.Serialize(weather, options);
Console.WriteLine(jsonStr);


public class WeatherForecast
{
    public required DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{

}

12.JsonContent.Create重载

现在可以使用剪裁安全协定或源生成的协定创建 [JsonContent] 实例。

var book = new Book(id: 1, "Peng's Story", "Peng", 2023);
HttpContent content = JsonContent.Create(book, BookSerializerContext.Default.Book);
//HttpContent content = JsonContent.Create(book, typeof(Book));

Console.WriteLine(await content.ReadAsStringAsync());


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

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

13.冻结JsonSerializerOptions实例

JsonSerializerOptions.MakeReadOnly()只读

使用新的 [IsReadOnly]属性可以检查选项实例是否已冻结。


WeatherForecast? weather = new WeatherForecast()
{
    Date = DateTime.Now,
    TemperatureCelsius = 26,
    Summary = "Hot"
};


var options = new JsonSerializerOptions
{
    TypeInfoResolver = WeatherForecastSerializerContext.Default.WithAddedModifier(static typeInfo =>
    {
        foreach (JsonPropertyInfo prop in typeInfo.Properties)
        {
            prop.Name = prop.Name.ToUpperInvariant() + "---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }
    }),
    WriteIndented = true
};

//options.MakeReadOnly();
options.WriteIndented = false;
options.MakeReadOnly();
Console.WriteLine(options.IsReadOnly);
var jsonStr = JsonSerializer.Serialize(weather, options);
//options.WriteIndented = false;
Console.WriteLine(jsonStr);
Console.WriteLine(options.IsReadOnly);


public class WeatherForecast
{
    public required DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class WeatherForecastSerializerContext : JsonSerializerContext
{

}

14.时间抽象

PeriodicTimer

  • 检索本地和 UTC 时间
  • 获取用于测量性能的时间戳
  • 创建计时器
var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(1));
using (periodicTimer)
{
    while (await periodicTimer.WaitForNextTickAsync())
    {
        try
        {
            await Task.Delay(3000);
            Console.WriteLine(DateTime.Now);
        }
        catch (Exception ex)
        {
        }
    }
}

15.Random随机填充和乱序方法

ReadOnlySpan<string> colors = new[] {
"Red",
"Green",
"Blue",
"Yellow"
};

// 根据colors数组随机生成35长度的数组
string[] roundArr = Random.Shared.GetItems(colors, 35);
Console.WriteLine(JsonSerializer.Serialize(roundArr));

// 对数组进行乱序
Random.Shared.Shuffle(roundArr);
Console.WriteLine(JsonSerializer.Serialize(roundArr));

16.高性能类型

16.1FrozenDictionary压力测试

安装包BenchmarkDotNet

image-20231110000240148

Release运行,开始执行不挑食

image-20231110000357016

压测代码

image-20231110000749876

[SimpleJob(RunStrategy.ColdStart, iterationCount: 10)]
public class FrozenDictionaryDemo
{
    public static Dictionary<string, string> dict = new Dictionary<string, string>() {
        { "apple","1"  },
        { "banana","2" },
        { "cherry","3" }
    };

    public static FrozenDictionary<string, string> fDict = dict.ToFrozenDictionary();
    public static HashSet<string> set = dict.Keys.ToHashSet<string>();
    public FrozenSet<string> fSet = set.ToFrozenSet<string>();

    [Benchmark]
    public void Run_Dictionary()
    {
        for (int i = 0; i < 100000000; i++)
        {
            dict.TryGetValue("banana", out _);
        }
    }


    [Benchmark]
    public void Run_FrozenDictionary()
    {
        for (int i = 0; i < 100000000; i++)
        {
            fDict.TryGetValue("banana", out _);
        }
    }

    [Benchmark]
    public void Run_HashSet()
    {
        for (int i = 0; i < 100000000; i++)
        {
            set.TryGetValue("banana", out _);
        }
    }

    [Benchmark]
    public void Run_FrozenSet()
    {
        for (int i = 0; i < 100000000; i++)
        {
            fSet.TryGetValue("banana", out _);
        }
    }

}

执行代码:

BenchmarkRunner.Run<FrozenDictionaryDemo>();

执行结果:

image-20231110000807522

16.2FrozenDictionary只读

[FrozenDictionary]和 [FrozenSet]。 创建集合后,这些类型就不允许对键和值进行任何更改。 此要求可实现更快的读取操作

image-20231110001149494

Dictionary<string, string> dict = new Dictionary<string, string>() {
        { "apple","1"  },
        { "banana","2" },
        { "cherry","3" }
    };
FrozenDictionary<string, string> fDict = dict.ToFrozenDictionary();
fDict.Remove("banana", out _);
Console.WriteLine(fDict.Count);

16.3SearchValues

SearchValues类型旨在传递给在传递的集合中查找任何值的第一个匹配项的方法。

var sw = Stopwatch.StartNew();
var str = "awsaiodupqowufjokaml;fe[pituihyreytuieklpsl;jck901238790537908l;sadnflkfcjkhsdfjdz";
var cStr = "z";
sw.Restart();
for (int i = 0; i < 100000000; i++)
{
    str.Contains(cStr);
}
Console.WriteLine(sw.ElapsedMilliseconds);

var sv = SearchValues.Create("wadyuiotirfyaopjflejgksem,.awopieyioutw4ei798901323ljkrsrdlktjz"u8);
byte cByte = (byte)"z"[0];
sw.Restart();
for (int i = 0; i < 100000000; i++)
{
    sv.Contains(cByte);
}
Console.WriteLine(sw.ElapsedMilliseconds);

17.键化 DI 服务

键化依赖项注入 (DI) 服务提供了一种使用键来注册和检索 DI 服务的方法。 通过使用键,可以限定注册和使用服务的方式。

导入包,需要使用NetCore远程的依赖注入容器

image-20231110004334996

<ItemGroup>
	<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

根据键值注入和生成

image-20231110004557753


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<IAnimal, Dog>("1");
builder.Services.AddKeyedSingleton<IAnimal, Cat>("2");
var app = builder.Build();
app.MapGet("/dog", ([FromKeyedServices("1")] IAnimal animal) => animal.Name);
app.MapGet("/cat", ([FromServices] IServiceProvider provider) =>
{
    IAnimal animal = provider.GetRequiredKeyedService<IAnimal>("2");
    return animal.Name;
});

app.Run();

public interface IAnimal
{
    string Name { get; }
}

public class Dog : IAnimal
{
    public string Name => "Dog";
}
public class Cat : IAnimal
{
    public string Name => "Cat";
}

运行:

image-20231110004638803

访问:

image-20231110004651115

18.Host生命周期

IHostedService:

  • StartAsync 开始
  • StopAsync 结束

现在 [IHostedLifecycleService]提供以下其他方法:

  • [StartingAsync(CancellationToken)] 开始前
  • [StartedAsync(CancellationToken)] 开始后
  • [StoppingAsync(CancellationToken)] 结束前
  • [StoppedAsync(CancellationToken)] 结束后

image-20231110010241829

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddHostedService<MyHostService>();

var app = builder.Build();

app.MapGet("/todo", () => "hello");

app.Run();


public class MyHostService : IHostedLifecycleService
{
    public Task StartAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StartAsync");
        return Task.CompletedTask;
    }

    public Task StartedAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StartedAsync");
        return Task.CompletedTask;
    }

    public Task StartingAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StartingAsync");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StopAsync");
        return Task.CompletedTask;
    }

    public Task StoppedAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StoppedAsync");
        return Task.CompletedTask;
    }

    public Task StoppingAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StoppingAsync");
        return Task.CompletedTask;
    }
}

运行:

image-20231110010346972

posted @   peng_boke  阅读(527)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示