You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中C#的foreach循环未用break却提前退出?

Unity NativeList foreach循环提前退出问题

场景与代码实现

需求是统计NativeList<int>中重复ID的出现次数,初始代码如下:

主循环逻辑

int currentId = -1;
int count = 0;
foreach (var item in rawItemList) {
    UnityEngine.Debug.LogFormat("Item {0}", item);
    if (currentId != item) {
        AddItem(currentId, count);
        count = 0;
    }
    currentId = item;
    count++;
    UnityEngine.Debug.LogFormat("Count {0}", count);
}

AddItem辅助函数

void AddItem(int itemId, int count) {
    UnityEngine.Debug.LogFormat("Add item {0} count {1}", itemId, count);
    if (count == 0) return;
    items.Add(itemId);
    counts.Add(count);
}

其中rawItemList、items、counts均为NativeList<int>类型,rawItemList包含元素:{0, 0, 2, 2, 3, 4, 4},循环前后打印该列表均能正常输出全部元素。

异常现象

第二次调用AddItem后,foreach循环直接终止,未遍历rawItemList剩余元素。控制台日志如下:

Item 0
Add item -1 count 0
Count 1
Item 0
Count 2
Item 2
Add item 0 count 2
Count 1
// 循环在此提前退出

补充信息

编辑1:改用for循环后运行正常

将foreach替换为标准for循环后,代码执行完全符合预期,疑问:foreach循环存在什么问题?

编辑2:完整结构体代码与调用逻辑

// public struct CountedItemList ...

public NativeList<int> items;
public NativeList<int> counts;

public CountedItemList(NativeList<int> rawItemList) {
    items = new NativeList<int>(Allocator.Temp);
    counts = new NativeList<int>(Allocator.Temp);
    if (rawItemList.Length == 0) return;
    rawItemList.Sort();
    int currentId = -1;
    int count = 0;
    foreach (var item in rawItemList) {
        UnityEngine.Debug.LogFormat("Item {0}", item);
        if (currentId != item) {
            AddItem(currentId, count);
            count = 0;
        }
        currentId = item;
        count++;
        UnityEngine.Debug.LogFormat("Count {0}", count);
    }
    AddItem(currentId, count);
}

调用代码:

NativeList<int> rawItemList = new NativeList<int>(Allocator.Temp);

// 填充元素逻辑

var cil = new CountedItemList(rawItemList);
rawItemList.Dispose();

编辑3:正常运行的for循环实现

for(int i = 0; i < rawItemList.Length; i++) {
    int item = rawItemList[i];
    // 后续统计逻辑与原foreach一致
}

问题原因

这是Unity NativeList的迭代器特性导致的:

  • NativeList的foreach循环依赖内部的**NativeArray<T>.Enumerator**,该迭代器在创建时会固定捕获NativeList当前的内存地址和元素长度,后续不会主动更新。
  • 循环内调用的AddItem会对items和counts执行Add操作,当这两个NativeList的容量不足时,Unity会触发非托管内存重新分配:申请新内存块、复制旧数据、释放原内存。
  • 这种内存操作会干扰rawItemList迭代器的内部状态,导致迭代器误判为已遍历到末尾,从而提前终止循环。

而for循环通过索引直接访问NativeList元素,每次访问都会实时读取rawItemList的当前内存地址和长度,完全不依赖迭代器对象,因此不受其他NativeList内存操作的影响。


内容的提问来源于stack exchange,提问作者Cansisti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:11:54