1.1 ref readonly
关于ref,一个主要应用是防止结构体拷贝,若返回的结构体不需要修改则用ref readonly:
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编辑
定义:
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); } }
使用:
RefStructTest refStructTest = new RefStructTest(); refStructTest.SetValues((ref int x, ref float b, ref float c, ref bool d) => { x = 24; b = 12.0f; c = 6.0f; d = true; });
fixed关键字可以固定内存地址,从而使用指针访问该地址,struct中的fixed字段可以实现struct内直接包含数组,
而不是链接到堆内存的数组。struct微软建议是将大小控制在24字节以内,虽然可以配合ref做到不频繁拷贝,但目前还没有明确的资料
确定不会产生性能影响。官方文档的fixed页面里也没有看见,所以谨慎使用吧。
通常指针和栈集合的分配可以使用spin,但unity目前没有集成spin以及对应的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个字符):
public unsafe struct StructString { private fixed char arr[8]; public void SetString(string str) { fixed (char* ptr = str) { for (int i = 0; i < str.Length; i++) { if (i > 7) break; arr[i] = ptr[i]; } } } 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; for (int i = 0; i < 8; i++) { char x = arr[i]; char y = other.arr[i]; if (x != y) { result = false; break; } } 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、指针这些内容。以上就是对这几样新功能的可用范围进行思考并编写的几个
小案例。最近比较忙就不做文章排版了,就当是记录吧。