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
下载完成后安装
检查命令
dotnet --list-sdks
1.2VS2022配置
安装完成后vs2022并没有net8环境
工具--->管理和预览(p)功能
使用.NET SDK预览版
重启之后新建项目
2.支持Half、Int128UInt128、序列化
代码
// [65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]
Console.WriteLine(JsonSerializer.Serialize(new object[] { Half.MaxValue, Int128.MaxValue, UInt128.MaxValue }));
如图
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 添加了对从接口层次结构序列化属性的支持。
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
。
如果程序设置JsonSerializerIsReflectionEnabledByDefault为false,还可通过代码TypeInfoResolver配置
代码如下:
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.非公共成员
可以使用 JsonIncludeAttribute 和 JsonConstructorAttribute 特性注释将非公共成员加入到给定类型的序列化协定中。
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运行访问即可
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
Release运行,开始执行不挑食
压测代码
[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>();
执行结果:
16.2FrozenDictionary只读
[FrozenDictionary]和 [FrozenSet]。 创建集合后,这些类型就不允许对键和值进行任何更改。 此要求可实现更快的读取操作
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远程的依赖注入容器
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
根据键值注入和生成
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";
}
运行:
访问:
18.Host生命周期
IHostedService:
- StartAsync 开始
- StopAsync 结束
现在 [IHostedLifecycleService]提供以下其他方法:
- [StartingAsync(CancellationToken)] 开始前
- [StartedAsync(CancellationToken)] 开始后
- [StoppingAsync(CancellationToken)] 结束前
- [StoppedAsync(CancellationToken)] 结束后
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;
}
}
运行:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!