学习c# 7.0-7.3的ref、fixed特性并在Unity下测试
1.ref的一些运用
1.1 ref readonly
关于ref,一个主要应用是防止结构体拷贝,若返回的结构体不需要修改则用ref readonly,类似c++的const标记 :
private ref readonly Attr PlayerSetting(Player player) { return ref player.attr; }
1.2 array ref
由于索引器不支持ref,所以目前只有数组的元素可以用ref:
int[] arr = new[] {1, 2, 3}; ref int item = ref arr[0]; //可用 //List<int> list = new List<int>(); //ref int item = ref list[0]; //报错
1.3 属性ref(返回值ref)
可以借由ref返回值的支持,给属性加上该关键字,以提示使用者优先考虑用ref方法读写
public class Player { private int mHp; public ref int Hp => ref mHp; }
1.4 多值ref
目前返回值不支持多ref返回,解构功能也不支持ref,但由于委托参数支持ref,因此可间接实现多字段ref编辑
使用:
RefStructTest refStructTest = new RefStructTest(); refStructTest.SetValues((ref int x, ref float y, ref float z, ref bool w) => { x = 24; y = 12.0f; z = 6.0f; w = true; });
定义:
public delegate void RefTestValueSet(ref int x, ref float y, ref float z, ref bool w); public struct RefStructTest { public int a; public float b; public float c; public bool d; public void SetValues(RefTestValueSet set) { set(ref a, ref b, ref c, ref d); } }
2.struct fixed的一些运用
fixed关键字可以固定内存地址,从而使用指针访问该地址,struct中的fixed字段可以实现struct内直接包含数组,
而不是链接到堆内存的数组。struct微软建议是将大小控制在16字节(后来也有24字节说法)以内,虽然可以配合ref做到不频繁拷贝,
但目前还没有明确的资料确定不会产生性能影响。
官方文档的fixed页面里也没有看见,所以谨慎使用吧。
通常指针和栈集合的分配可以使用spin,但unity目前没有集成spin以及对应的dll。
(也可以参考ZString(https://github.com/Cysharp/ZString),把相关dll丢进来用)
fixed本身并不是一个新功能,但在7.x版本后对其进行了增强。
unity可以通过AssemblyDefinition实现局部的unsafe code功能,下面的一些unsafe特性代码也是定义
在一个unsafe库中。
2.1 一个理论上可以实现的栈数组
public unsafe struct StructArray { private fixed int arr[8]; public void SetArr(int index, int value) { arr[index] = value; } public ref int GetArrValue(int index) { return ref arr[index]; } }
通过函数接口的调用,外部代码不需要访问指针即可在栈中使用数组,
简单的测试一下:
StructArray structArray = new StructArray(); structArray.SetArr(0, 10); structArray.SetArr(1, 20); structArray.SetArr(2, 30); Debug.Log(structArray.GetArrValue(0));//10 Debug.Log(structArray.GetArrValue(1));//20 Debug.Log(structArray.GetArrValue(2));//30
2.2 一个简单的栈string结构
因为string是个分配在堆上的结构,且修改会重新创建,有性能开销。
因此有许多优化string的方案,这里我们可以分配栈上的char[]来做一些优化(测试代码,只支持8个字符):
using System; public unsafe struct StructString { private fixed char arr[8]; public void SetString(string str) { fixed (char* dstPtr = arr) { fixed (char* srcPtr = str) { Buffer.MemoryCopy(srcPtr, dstPtr, 16L, 16L); } } } public string GetString() { string result = string.Empty; fixed (char* ptr = arr) { result = new string(ptr); } return result; } public bool EqulasCheck(StructString other) { bool result = true; fixed (char* xPtr = &arr[0])//16字节,只需要做2次long类型判断 { char* yPtr = other.arr; if (*(long*) xPtr != *(long*) yPtr) { result = false; } else if (*(long*) (xPtr + 4) != *(long*) (yPtr + 4)) { result = false; } } return result; } }
使用:
StructString str = new StructString(); str.SetString("qwe");//qwe Debug.Log(str.GetString()); StructString str2 = new StructString(); str2.SetString("qwe");//true Debug.Log(str.EqulasCheck(str2));
可以看见,封装之后外部代码可以不接触unsafe、指针这些内容。以上就是对这几样新功能的可用范围进行思考并编写的一些
小案例。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2015-10-19 python字符串操作,以及对应的C#实现