今天整理了.NET 10类库新增的几个常用功能,按老规矩,分享给大家:
1. ISOWeek for DateOnly 类型的新方法重载
最初设计的 ISOWeek 类主要是为了专门使用 DateTime,因为它是在 DateOnly 类型出现之前引入的。 既然DateOnly现在可用了,那么ISOWeek也有必要支持它。 以下重载是新引入的:
GetWeekOfYear(DateOnly)
GetYear(DateOnly)
ToDateOnly(Int32, Int32, DayOfWeek)
2.用于字符串比较的数字排序
数值字符串比较是一项高度请求的功能,用于在数字上而不是按词法比较字符串。
例如,2小于10,因此"2"应按数字顺序在"10"前显示。
同样,"2" 和 "02" 在数值上是相等的。 使用新 NumericOrdering 选项,现在可以执行以下类型的比较:
StringComparer numericStringComparer = StringComparer.Create(CultureInfo.CurrentCulture, CompareOptions.NumericOrdering);Console.WriteLine(numericStringComparer.Equals("02", "2")); // Output: Trueforeach (string os in new[] { "Windows 8", "Windows 10", "Windows 11" }.Order(numericStringComparer)) {Console.WriteLine(os); }// Output: // Windows 8 // Windows 10 // Windows 11 HashSet<string> set = new HashSet<string>(numericStringComparer) { "007" }; Console.WriteLine(set.Contains("7")); // Output: True
不适用于以下基于索引的字符串操作:IndexOf、LastIndexOf、StartsWith、EndsWith、IsPrefix和IsSuffix。
3. 支持单个参数的新 TimeSpan.FromMilliseconds 重载
之前引入了 TimeSpan.FromMilliseconds(Int64, Int64) 方法,但未添加采用单个参数的重载。
尽管这是由于第二个参数是可选的,但在 LINQ 表达式中使用时会导致编译错误,例如:
Expression<Action> a = () => TimeSpan.FromMilliseconds(1000);
4.TryAdd 的附加 TryGetValue 和 OrderedDictionary<TKey, TValue> 重载
OrderedDictionary<TKey,TValue> 提供 TryAdd 和 TryGetValue 以进行添加和检索,就像任何其他 IDictionary<TKey, TValue> 实现一样。 但是,在某些情况下,你可能想要执行更多操作,因此会添加新的重载,以便返回一个条目的索引。
TryAdd(TKey, TValue, Int32)
TryGetValue(TKey, TValue, Int32)
可以使用此索引与GetAt和SetAt一起快速访问条目。 新 TryAdd 重载的示例用法是在有序字典中添加或更新键值对:
// Try to add a new key with value 1. if (!orderedDictionary.TryAdd(key, 1, out int index)) {// Key was present, so increment the existing value instead.int value = orderedDictionary.GetAt(index).Value;orderedDictionary.SetAt(index, value + 1); }
新 API 已在 JsonObject 中使用,并将更新属性的性能提高了 10-20%。
5. 支持在 JsonSourceGenerationOptions 中指定 ReferenceHandler
public static void MakeSelfRef() {SelfReference selfRef = new SelfReference();selfRef.Me = selfRef;Console.WriteLine(JsonSerializer.Serialize(selfRef, ContextWithPreserveReference.Default.SelfReference));// Output: {"$id":"1","Me":{"$ref":"1"}} }[JsonSourceGenerationOptions(ReferenceHandler = JsonKnownReferenceHandler.Preserve)] [JsonSerializable(typeof(SelfReference))] internal partial class ContextWithPreserveReference : JsonSerializerContext { }internal class SelfReference {public SelfReference Me { get; set; } = null!; }
6. 禁止重复 JSON 属性的选项
JSON 规范不指定在反序列化 JSON 有效负载时如何处理重复属性。 这可能会导致意外的结果和安全漏洞。
.NET 10 引入了 JsonSerializerOptions.AllowDuplicateProperties 禁止重复 JSON 属性的选项:
string json = """{ "Value": 1, "Value": -1 }"""; Console.WriteLine(JsonSerializer.Deserialize<MyRecord>(json).Value); // -1 JsonSerializerOptions options = new() { AllowDuplicateProperties = false }; JsonSerializer.Deserialize<MyRecord>(json, options); // throws JsonException JsonSerializer.Deserialize<JsonObject>(json, options); // throws JsonException JsonSerializer.Deserialize<Dictionary<string, int>>(json, options); // throws JsonException JsonDocumentOptions docOptions = new() { AllowDuplicateProperties = false }; JsonDocument.Parse(json, docOptions); // throws JsonException record MyRecord(int Value);
通过检查反序列化期间同一属性是否被多次赋值来检测重复项。因此,该机制在处理大小写敏感度和命名策略等其他选项时,也能正常工作。
7. ZipArchive 性能和内存改进
.NET 10 提高了 ZipArchive 的性能和内存使用率。
首先,优化了在 ZipArchive 模式下将条目写入 Update 的方式。 以前,所有 ZipArchiveEntry 实例都加载到内存中并重写,这可能会导致内存使用率和性能瓶颈较高。 优化可减少内存使用率,并避免需要将所有条目加载到内存中,从而提高性能。
其次,条目的 ZipArchive 提取现已并行化,并且内部数据结构经过优化,以便更好地使用内存。 这些改进解决了与性能瓶颈和高内存使用率相关的问题,提高了 ZipArchive 效率和速度更快,尤其是在处理大型存档时。
8. 新异步 ZIP API
.NET 10 引入了新的异步 API,使读取或写入 ZIP 文件时执行非阻塞作更容易。 社区高度要求此功能。
新 async 方法可用于提取、创建和更新 ZIP 存档。 这些方法使开发人员能够有效地处理大型文件并提高应用程序响应能力,尤其是在涉及 I/O 绑定作的方案中。 这些方法包括:
- ZipArchive.CreateAsync(Stream, ZipArchiveMode, Boolean, Encoding, CancellationToken)
- ZipArchiveEntry.OpenAsync(CancellationToken)
- ZipFile.CreateFromDirectoryAsync
- ZipFile.ExtractToDirectoryAsync
- ZipFile.OpenAsync
- ZipFile.OpenReadAsync(String, CancellationToken)
- ZipFileExtensions.CreateEntryFromFileAsync
- ZipFileExtensions.ExtractToDirectoryAsync
- ZipFileExtensions.ExtractToFileAsync
9. 新进程组中启动 Windows 进程
对于 Windows,你现在可以用于 ProcessStartInfo.CreateNewProcessGroup 在单独的进程组中启动进程。
这样就可以将隔离的信号发送到子进程,否则无需正确处理即可关闭父进程。 发送信号十分方便,以避免强制终止。
using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading;class Program {static void Main(string[] args){bool isChildProcess = args.Length > 0 && args[0] == "child";if (!isChildProcess){var psi = new ProcessStartInfo{FileName = Environment.ProcessPath,Arguments = "child",CreateNewProcessGroup = true,};using Process process = Process.Start(psi)!;Thread.Sleep(5_000);GenerateConsoleCtrlEvent(CTRL_C_EVENT, (uint)process.Id);process.WaitForExit();Console.WriteLine("Child process terminated gracefully, continue with the parent process logic if needed.");}else{// If you need to send a CTRL+C, the child process needs to re-enable CTRL+C handling, if you own the code, you can call SetConsoleCtrlHandler(NULL, FALSE).// see https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#remarksSetConsoleCtrlHandler((IntPtr)null, false);Console.WriteLine("Greetings from the child process! I need to be gracefully terminated, send me a signal!");bool stop = false;var registration = PosixSignalRegistration.Create(PosixSignal.SIGINT, ctx =>{stop = true;ctx.Cancel = true;Console.WriteLine("Received CTRL+C, stopping...");});StreamWriter sw = File.AppendText("log.txt");int i = 0;while (!stop){Thread.Sleep(1000);sw.WriteLine($"{++i}");Console.WriteLine($"Logging {i}...");}// Clean up sw.Dispose();registration.Dispose();Console.WriteLine("Thanks for not killing me!");}}private const int CTRL_C_EVENT = 0;private const int CTRL_BREAK_EVENT = 1;[DllImport("kernel32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]private static extern bool SetConsoleCtrlHandler(IntPtr handler, [MarshalAs(UnmanagedType.Bool)] bool Add);[DllImport("kernel32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]private static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId); }
周国庆
2025/12/22