C# 中的 in 参数和性能分析

本文探讨了C#中in参数的引入原因,性能提升,尤其是在Parallel.For中的应用,同时提醒了使用时的注意事项和潜在限制。in参数通过引用传递,避免了大结构体复制的成本,提升了代码性能,但与可变结构体结合可能导致意外行为。建议仅在不可修改的只读结构体上使用以确保最佳效果。
摘要由CSDN通过智能技术生成

in 修饰符也是从 C# 7.2 开始引入的,它与我们上一篇中讨论的 《C# 中的只读结构体(readonly struct)1 是紧密相关的。

in 修饰符

in 修饰符通过引用传递参数。 它让形参成为实参的别名,即对形参执行的任何操作都是对实参执行的。 它类似于 refout 关键字,不同之处在于 in 参数无法通过调用的方法进行修改。

  • ref 修饰符,指定参数由引用传递,可以由调用方法读取或写入。
  • out 修饰符,指定参数由引用传递,必须由调用方法写入。
  • in 修饰符,指定参数由引用传递,可以由调用方法读取,但不可以写入。

举个简单的例子:

struct Product
{
   
    public int ProductId {
    get; set; }
    public string ProductName {
    get; set; }
}

public static void Modify(in Product product)
{
   
    //product = new Product();          // 错误 CS8331 无法分配到 变量 'in Product',因为它是只读变量
    //product.ProductName = "测试商品";  // 错误 CS8332 不能分配到 变量 'in Product' 的成员,因为它是只读变量
    Console.WriteLine($"Id: {product.ProductId}, Name: {product.ProductName}"); // OK
}

引入 in 参数的原因

我们知道,结构体实例的内存在栈(stack)上进行分配,所占用的内存随声明它的类型或方法一起回收,所以通常在内存分配上它是比引用类型占有优势的。2

但是对于有些很大(比如有很多字段或属性)的结构体,将其作为方法参数,在紧凑的循环或关键代码路径中调用方法时,复制这些结构的成本就会很高。当所调用的方法不修改该参数的状态,使用新的修饰符 in 声明参数以指定此参数可以按引用安全传递,可以避免(可能产生的)高昂的复制成本,从而提高代码运行的性能。

in 参数对性能的提升

为了测试 in 修饰符对性能的提升,我定义了两个较大的结构体,一个是可变的结构体 NormalStruct,一个是只读的结构体 ReadOnlyStruct,都定义了 30 个属性,然后定义三个测试方法:

  • DoNormalLoop 方法,参数不加修饰符,传入一般结构体,这是以前比较常见的做法。
  • DoNormalLoopByIn 方法,参数加 in 修饰符,传入一般结构体。
  • DoReadOnlyLoopByIn 方法,参数加 in 修饰符,传入只读结构体。

代码如下所示:

public struct NormalStruct
{
   
    public decimal Number1 {
    get; set; }
    public decimal Number2 {
    get; set; }
    //...
    public decimal Number30 {
    get; set; }
}

public readonly struct ReadOnlyStruct
{
   
    // 自动属性上的 readonly 关键字是可以省略的,这里加上是为了便于理解
    public readonly decimal Number1 {
    get; }
    public readonly decimal Number2 {
    get; }
    //...
    public readonly decimal Number30 {
    get; }
}

public class BenchmarkClass
{
   
    const int loops = 50000000;
    NormalStruct normalInstance = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值