关于c# 7.0-7.3的ref、fixed特性在Unity下测试

1.ref的一些运用

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;
});

 

2.struct fixed的一些运用

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、指针这些内容。以上就是对这几样新功能的可用范围进行思考并编写的几个

小案例。最近比较忙就不做文章排版了,就当是记录吧。

上一篇:Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解


下一篇:利用bootstrap3的分页样式和jq实现分页功能