zoukankan      html  css  js  c++  java
  • 学习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编辑

    使用:

    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。

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

    小案例。

  • 相关阅读:
    一个简单的随机数生成算法实现(C++)
    gabor 滤波的c++实现与该类得使用简介
    嵌入式软件的覆盖测试
    scanf()函数用法小结(转载)
    创建动态2维vector (C++)
    HDU 1086 You can Solve a Geometry Problem too
    计算几何多边形的重心
    HDU 1711 Number Sequence
    HDU 2602 Bone Collector
    计算几何基础篇
  • 原文地址:https://www.cnblogs.com/hont/p/15426547.html
Copyright © 2011-2022 走看看