如何在C#中生成指针数组?代码优化场景求助
解决方案:简化Unity Tick检查逻辑的正确实现
为什么你的写法报错
int*[] ticks = new int*[4];:C#中直接使用指针需要开启unsafe上下文,Unity默认禁用该选项,且裸指针容易因GC内存移动引发错误,需配合fixed关键字固定变量地址,不推荐在Unity项目中随意使用。ref int[] ticks = new ref int[4];:C#语法不支持直接创建引用类型数组,这种写法本身就不符合语言规范。
推荐方案:安全的无指针实现(无需unsafe)
通过提取通用逻辑+辅助方法/结构体的方式,既精简代码又避免内存风险,以下提供两种简洁实现:
方案1:提取通用处理方法(最易维护)
把重复的Tick检查逻辑封装成一个私有方法,然后逐个传入状态和Tick变量的引用,代码可读性高,兼容性强:
private void CheckTicks() { // 封装通用Tick检查逻辑 void ProcessTick(ref bool state, ref int tick, bool invertedCheck = false, Action onComplete = null) { bool shouldCheck = invertedCheck ? state : !state; if (shouldCheck) { if (tick >= DEFAULT_CYCLE_END_VALUE) { tick = DEFAULT_CYCLE_START_VALUE; state = !state; onComplete?.Invoke(); } else { tick++; } } } // 批量调用处理方法 ProcessTick(ref canEatFood, ref canEatTick); ProcessTick(ref canTakeBath, ref canBatheTick); ProcessTick(ref canPlay, ref canPlayTick); ProcessTick(ref beenPet, ref beenPetTick, true, CheckIfPetsShouldKill); }
方案2:使用Ref Struct批量遍历(C# 7.3+支持)
通过自定义ref struct存储状态和Tick的引用,再用Span批量遍历处理,适合变量数量较多的场景:
// 定义仅用于栈的引用结构体,避免堆内存分配 private ref struct TickStatePair { public ref bool State; public ref int Tick; public bool IsInvertedCheck; // 标记是否反向检查(如beenPet是true时触发) public Action OnTickComplete; // Tick完成后的回调 } private void CheckTicks() { // 创建Span存储所有状态-Tick配对 var tickPairs = new Span<TickStatePair>(new[] { new TickStatePair { State = ref canEatFood, Tick = ref canEatTick, IsInvertedCheck = false }, new TickStatePair { State = ref canTakeBath, Tick = ref canBatheTick, IsInvertedCheck = false }, new TickStatePair { State = ref canPlay, Tick = ref canPlayTick, IsInvertedCheck = false }, new TickStatePair { State = ref beenPet, Tick = ref beenPetTick, IsInvertedCheck = true, OnTickComplete = CheckIfPetsShouldKill } }); // 遍历处理所有配对 foreach (ref var pair in tickPairs) { bool shouldCheck = pair.IsInvertedCheck ? pair.State : !pair.State; if (shouldCheck) { if (pair.Tick >= DEFAULT_CYCLE_END_VALUE) { pair.Tick = DEFAULT_CYCLE_START_VALUE; pair.State = !pair.State; pair.OnTickComplete?.Invoke(); } else { pair.Tick++; } } } }
可选方案:Unsafe指针实现(不推荐)
如果一定要用指针,需先在Unity编辑器中开启Allow unsafe code(路径:Edit > Project Settings > Player > Other Settings > Allow unsafe code),再使用以下代码:
private unsafe void CheckTicks() { // 固定变量地址,防止GC移动内存 fixed (int* eatTickPtr = &canEatTick, bathTickPtr = &canBatheTick, playTickPtr = &canPlayTick, petTickPtr = &beenPetTick) fixed (bool* eatStatePtr = &canEatFood, bathStatePtr = &canTakeBath, playStatePtr = &canPlay, petStatePtr = &beenPet) { int*[] tickPtrs = { eatTickPtr, bathTickPtr, playTickPtr, petTickPtr }; bool*[] statePtrs = { eatStatePtr, bathStatePtr, playStatePtr, petStatePtr }; bool[] invertedChecks = { false, false, false, true }; Action[] callbacks = { null, null, null, CheckIfPetsShouldKill }; for (int i = 0; i < tickPtrs.Length; i++) { bool shouldCheck = invertedChecks[i] ? *statePtrs[i] : !*statePtrs[i]; if (shouldCheck) { if (*tickPtrs[i] >= DEFAULT_CYCLE_END_VALUE) { *tickPtrs[i] = DEFAULT_CYCLE_START_VALUE; *statePtrs[i] = !*statePtrs[i]; callbacks[i]?.Invoke(); } else { (*tickPtrs[i])++; } } } } }
注意:指针写法可读性差,易引发内存错误,仅在极端性能需求场景下考虑使用。
内容的提问来源于stack exchange,提问作者Dylan Beaulieu
相关产品推荐
相关产品推荐

