在Unity游戏开发中,Dictionary
和List
是最核心的两种数据结构,它们各自有优势和应用场景。以下是介绍:
🧠 数据结构本质对比
特性 | Dictionary<TKey, TValue> | List |
---|---|---|
底层结构 | 哈希表(Hash Table) | 动态数组(Dynamic Array) |
查找效率 | O(1) 按键查找 | O(n) 遍历查找 |
插入/删除效率 | O(1) ~ O(n) (哈希冲突时) | O(n) (需移位) |
内存占用 | 较高(存储哈希桶和指针) | 较低(连续内存) |
数据顺序 | 无序 | 严格顺序 |
核心优势 | 键值配对 + 高速查找 | 顺序访问 + 随机索引 |
各自擅长领域
**Dictionary **
// 典型案例:用ID快速定位游戏对象
Dictionary<int, Enemy> _enemyDict = new Dictionary<int, Enemy>();
void SpawnEnemy(int id) {
Enemy prefab = Resources.Load<Enemy>($"Enemies/{id}");
Enemy enemy = Instantiate(prefab);
_enemyDict.Add(id, enemy); // O(1)插入
}
Enemy GetEnemy(int id) {
return _enemyDict.TryGetValue(id, out Enemy e) ? e : null; // O(1)查找
}
适用场景:
✅ 通过唯一ID查找对象(玩家/敌人/NPC)
✅ 建立资源路径与实例映射(如:“Weapons/Sword” → 预制体)
✅ 实时数据索引(成就ID → 完成状态)
✅ 避免重复添加(用ContainsKey
检查存在性)
📜 **List **
// 典型案例:游戏对象批量处理
List<Bullet> _activeBullets = new List<Bullet>();
void UpdateBullets() {
for(int i = 0; i < _activeBullets.Count; ) {
if(_activeBullets[i].IsExpired) {
_activeBullets.RemoveAt(i); // 移除时需小心索引变化
} else {
_activeBullets[i++].Update();
}
}
}
// 添加新子弹
void FireBullet() {
Bullet b = _bulletPool.Get();
_activeBullets.Add(b); // O(1)尾部添加
}
适用场景:
✅ 需要严格顺序的数据(对话文本序列)
✅ 需高频遍历的集合(每帧更新所有子弹)
✅ 动态增减的集合(背包物品、技能冷却队列)
✅ 需要排序操作的场景(玩家积分排行榜)
经典组合应用
1. 背包系统(高性能实现)
Dictionary<int, ItemData> _itemDB; // 静态数据表:ID->属性
Dictionary<int, ItemInstance> _inventoryDict; // 库存实例:ID->实例
List<ItemInstance> _inventoryList; // 显示用有序列表
void AddItem(int itemId, int count) {
// 1. 从字典快速检查存在性
if(_inventoryDict.TryGetValue(itemId, out ItemInstance instance)) {
instance.count += count; // 堆叠
} else {
// 2. 创建新实例
ItemData data = _itemDB[itemId]; // 从静态字典取数据
instance = new ItemInstance(data, count);
// 3. 同步双结构
_inventoryDict.Add(itemId, instance);
_inventoryList.Add(instance);
}
// 4. 列表排序(List专长)
_inventoryList.Sort(SortByRarity);
}
// 排序逻辑(List专属操作)
int SortByRarity(ItemInstance a, ItemInstance b) {
return b.data.rarity.CompareTo(a.data.rarity);
}
⚡️ 2. 对象池系统(高效复用)
Dictionary<GameObject, List<GameObject>> _pool =
new Dictionary<GameObject, List<GameObject>>();
GameObject Spawn(GameObject prefab) {
// 1. 字典查找对应对象池
if(!_pool.TryGetValue(prefab, out List<GameObject> list)) {
list = new List<GameObject>();
_pool.Add(prefab, list);
}
// 2. 列表查找可用对象
foreach(GameObject obj in list) {
if(!obj.activeInHierarchy) return obj;
}
// 3. 列表无可用则创建新对象
GameObject newObj = Instantiate(prefab);
list.Add(newObj); // 加入List
return newObj;
}
🛡️ 3. 技能管理系统
Dictionary<string, SkillData> _skillDB; // ID->技能配置
List<ActiveSkill> _activeSkills; // 激活中技能列表
void CastSkill(string skillId) {
// 1. 从字典读取基础数据(O(1))
SkillData data = _skillDB[skillId];
// 2. 创建技能实例
ActiveSkill skill = new ActiveSkill(data);
// 3. 加入List进行更新
_activeSkills.Add(skill);
}
void Update() {
// 4. 遍历List更新技能(顺序重要!)
for(int i=0; i<_activeSkills.Count; i++) {
_activeSkills[i].Update();
}
}
⚠️ 避坑指南
字典遍历陷阱
// 错误!修改集合时不能遍历 foreach(var key in _dict.Keys) { if(condition) _dict.Remove(key); // 抛出InvalidOperationException } // 正确做法 List<TKey> keysToRemove = new List<TKey>(); foreach(var key in _dict.Keys) { if(condition) keysToRemove.Add(key); } foreach(var key in keysToRemove) { _dict.Remove(key); }
列表删除优化
// 正序删除导致索引错乱 for(int i=0; i<list.Count; i++) { if(condition) list.RemoveAt(i--); // 需手动调整索引 } // 倒序删除更安全 for(int i=list.Count-1; i>=0; i--) { if(condition) list.RemoveAt(i); }
空值防御
// 字典安全访问 if(_dict.TryGetValue(key, out var value)) { // 安全操作value } // 列表边界检查 if(index >= 0 && index < list.Count) { var item = list[index]; }
如何选择 
!:
- 频繁查找 + 无序数据 → Dictionary
- 顺序访问/修改 → List
- 需要两者特性 → Dictionary与List联动
在Unity 2023+版本中,可考虑HashSet
(无值字典)或LinkedList
(高效增删),但Dictionary+List组合仍是90%游戏系统的首选,尤其在需要高性能查询和灵活排序的场景中。