面向云技术架构 - 痴者工良

  • 首页
  • 工良写的电子书
    • kubernetes 教程
    • 从 C# 入门 Kafka
    • 多线程和异步
    • 动态编程-反射、特性、AOP
    • 表达式树
  • 本站文章导航
  • 隐私政策
愿有人陪你颠沛流离
遇到能让你付出的事物或者人,都是一种运气。
能遇到,就该珍惜。或许你们最终没能在一起,但你会切实地感受到力量。
正因为这样,那段相遇才变得有价值,才没有辜负这世间的每一段相遇。
  1. 首页
  2. .NET
  3. 正文

C# 结构体在数组中传递时保持引用

2022年10月25日 416点热度 1人点赞 0条评论
内容纲要

因为结构体或者值类型在传递时,是值复制,导致传递后修改其值,原先的值不会发生改变。
即使使用 ref 做参数,也没法改变传递数组是值复制的问题。
阅读 .NET 源码是发现了 .NET 6 的一个 API,可以很方便完成这个任务,让结构体像引用类型一样。

using System.Runtime.InteropServices;

public class Progarm
{
     static void Main()
    {
        var a = new A[100];
        var span = a.AsSpan();
        ref A c = ref MemoryMarshal.GetReference(span);
        c.B = "1111";

    }
}
public struct A
{
    public string B
    {
        get; set;
    }
}

file

如果要获取指定位置的指针,可以使用:

        ref A d = ref Unsafe.Add(ref c, 1);
     static void Main()
    {
        var a = new A[100];
        var span = a.AsSpan();
        ref A c = ref MemoryMarshal.GetReference(span);
        c.B = "0";
        ref A d = ref Unsafe.Add(ref c, 1);
        d.B = "1";
        ref A e = ref Unsafe.Add(ref c, 2);
        e.B = "2";
    }

这样可以访问基于 c 开始的,指定位置的值。

.NET 源代码就使用这种方式反转结构体数组(Span<T>) 的内容:

        public static void Reverse<T>(this Span<T> span)
        {
            ref T p = ref MemoryMarshal.GetReference(span);
            int i = 0;
            int j = span.Length - 1;
            while (i < j)
            {
                T temp = Unsafe.Add(ref p, i);
                Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j);
                Unsafe.Add(ref p, j) = temp;
                i++;
                j--;
            }
        }

通过 Span 获取结构体指针的原理:

        public static ref T GetReference<T>(Span<T> span)
        {
            if (span.Pinnable == null)
                unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
            else
                return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
        }

源码位置:System.Runtime.InteropServices、MemoryMarshal。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: c 传递 体在 引用 数组
最后更新:2022年10月25日

痴者工良

高级程序员劝退师

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2022 whuanle.cn. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备18051778号

粤公网安备 44030902003257号