使用 C# 13 参数集合可以更轻松、更快速地调用方法

使用 C# 13 参数集合可以更轻松、更快速地调用方法

编码文章call10242024-12-23 8:58:0317A+A-

点击蓝字

关注我们

作者:Kathleen Dollard

排版:Rani Sun



C# 13 提供的功能让您能够更轻松、更安全、更快速地以您熟悉和喜爱的风格编写代码。您可以在 C# 13 中的新增功能中找到 C# 13 功能的完整列表。


C# 13 实现了一项长期以来的功能请求,现在允许集合表达式支持的任何集合类型作为params参数,而不仅仅是数组。此功能基于 C# 12 中引入的集合表达式功能。

C# 13 中的新增功能

https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-13



使用集合表达式奠定基础

C# 12 中引入了集合表达式,为以前创建各种集合的无数种方法提供了一种替代方法。在方法上下文中,这允许您在许多场景中简化集合的使用,包括调用方法:

// C# 12 之前WriteByteArray(new[] { (byte)1, (byte)2, (byte)3 });WriteByteSpan(stackalloc[] { (byte)1, (byte)2, (byte)3 });
// C# 12 之后WriteByteArray([1, 2, 3]);WriteByteSpan([1, 2, 3]);
static void WriteByteArray(byte[] bytes) { }static void WriteByteSpan(Span<byte> bytes) { }

这也使我们能够统一 C# 处理集合的方式。请注意,集合表达式可以推断集合的类型和成员的类型。



params数组

params 自 C# 1.0 以来就一直存在于该语言中。它允许调用代码以逗号分隔的列表形式包含零到多个参数。该方法以数组形式接收此列表,该列表可能为空:

WriteByteArray(1, 2, 3);WriteByteArray();
static void WriteByteArray(params byte[] bytes) { }

在 C# 13 之前,必须在方法的参数列表中将 params 声明为数组。


除了使用值列表进行调用外,您还可以使用数组调用带有 params 参数的方法。并且从 C# 12 开始,它可以是集合表达式:

WriteByteArray(1, 2, 3);WriteByteArray([1, 2, 3]);byte[] bytes = [4, 5];WriteByteArray([1, 2, 3, .. bytes]);
static void WriteByteArray(params byte[] bytes) { }



params 集合

从 C# 13 开始,params 可以是任何支持集合表达式的集合类型:

WriteByteSpan(1, 2, 3);WriteByteSpan();
static void WriteByteSpan(params Span<byte> bytes) { }

虽然这似乎是一个很小的变化,但它通常可以让编译器优化您的代码。例如,如果该方法使用 params Span,则编译器可以使用堆栈空间为该方法创建Span。这比分配数组的性能更好。


使用特定类型还可以向调用者传达集合的使用方式。例如,params IReadonlyList<T>表示集合不会被修改。


如果您使用 params IEnumerable<T>,则用户可以传递文字值列表、数组、List<T>、任何实现 IEnumerable的集合类型或 LINQ 表达式:

WriteByteArray(1, 2, 3);
byte[] bytes = [1, 2, 3, 4, 5];WriteByteArray(bytes.Where(x => x < 4));
static void WriteByteArray(params IEnumerable<byte> bytes) { }

当 params 接收器是接口并且参数是元素的离散列表或集合表达式时,编译器将使用具体类型。许多集合接口都有一个逻辑上合理的默认实现,例如 IReadonlyList<T>对应ReadonlyCollection<T>。由于 IEnumerable<T>没有如此明显的选择,并且对 .NET 至关重要,因此它对 param 和集合表达式都使用了一种特殊的高性能类型。



重载

C# 支持重载方法 - 这意味着如果参数类型不同,则可以存在多个同名方法。您可以像重载其他参数一样对 params 集合进行重载。

public class ParamCollections{ public static void Overloads() { WriteNumbers(1, 2, 3); WriteNumbers([1, 2, 3]); WriteNumbers(new[] { 1, 2, 3 }); byte[] ints = [1, 2, 3, 4, 5]; WriteNumbers(ints.Where(x => x < 4));
}
// 此代码从静态本地函数转变为私有函数 // 因为局部函数不允许重载。 private static void WriteNumbers<T>(params IEnumerable<T> values) => Console.WriteLine("IEnumerable"); private static void WriteNumbers<T>(params ReadOnlySpan<T> values) => Console.WriteLine("Span");}
// 结果是:// // Span// Span// Span// IEnumerable

例如,您可能在同一个解析范围内有一个带有 params IEnumerable<T>的重载和一个带有 params ReadOnlySpan<T>的重载。如果您传递一个值列表,则将选择 params ReadOnlySpan<T>重载。如果您传递一个数组,则也将选择 params ReadOnlySpan<T>重载,因为从数组到 ReadOnlySpan<T>存在隐式转换。如果您传递 List<T>,则将使用 params IEnumerable<T>重载:

public class ParamCollections{ public static void Overloads() { WriteNumbers(1, 2, 3); WriteNumbers([1, 2, 3]); WriteNumbers(new[] { 1, 2, 3 }); byte[] ints = [1, 2, 3, 4, 5]; WriteNumbers(ints.Where(x => x < 4));
}
// 此代码从静态本地函数转变为私有函数 // 因为局部函数不允许重载。 private static void WriteNumbers<T>(params IEnumerable<T> values) => Console.WriteLine("IEnumerable"); private static void WriteNumbers<T>(params ReadOnlySpan<T> values) => Console.WriteLine("Span");}
// 结果是:// // Span// Span// Span// IEnumerable

编译器会为您挑选一个合理的重载。如果 Span可用,它通常会被优先选择,因为这样可以避免在方法调用中进行内存分配。


无论您是否将 params 集合添加到您自己的代码中,它们都会使您的应用程序运行得更快,因为 .NET 运行时库现在可以在更多地方使用 Span等高性能类型。您可以使用与 params 相同的概念,调用者在如何调用方法方面具有更大的灵活性,并且编译器将选择重载。



考虑重载

重载是 C# 的一个非常强大的功能。但与许多强大的功能一样,正确使用它非常重要。如果有多个同名的方法,它们应该执行相同的操作。它们在执行方式或性能上可能有所不同,但更改传递的类型不会给您的应用程序带来重大更改。通常,这意味着在调整参数值后调用单个实现。


如上例所示,调用代码的微小变化可能会导致调用不同的重载。对于所有 C# 应用程序来说都是如此,无论您是否使用 params 集合。



总结

我们对 C# 13 中的参数集合感到非常兴奋,迫不及待地想听听您的想法!


您可以在 C# 13 中的新增功能中了解 C# 13 中的所有功能。

C# 13 中的新增功能

https://devblogs.microsoft.com/semantic-kernel/microsoft-extensions-ai-simplifying-ai-integration-for-net-partners/


点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4