如何编写无空值异常的Linq查询,高效筛选满足条件的GameObject
Linq筛选Unity GameObject的规范实现
现有代码的可优化点
你之前拆分两个Where的写法虽然能正常规避空引用,但存在两个明确的性能与可读性问题:
- 重复组件查询:对同一个GameObject连续两次调用
GetComponent<Cars>(),而Unity的GetComponent本质是遍历对象挂载组件的查找操作,重复调用会产生不必要的查找开销 - 冗余遍历流程:拆分两个Where意味着框架需要对
m_ItemList的元素完成两次全量遍历,远低于单次遍历的执行效率
推荐实现方案
最高效的零重复查询写法
通过Linq的投影操作缓存组件引用,彻底避免重复查找:
itemBought = m_ItemList .Select(go => new { TargetGo = go, CarComponent = go.GetComponent<Cars>() }) .Where(item => item.CarComponent != null && item.CarComponent.Bought) .Select(item => item.TargetGo) .ToList();
实现优势:
- 每个GameObject仅执行一次
GetComponent<Cars>(),无重复查询的性能损耗 - 空判断前置,组件不存在时直接跳过后续判断,从根源上避免空引用异常
- 单次遍历完成全部筛选逻辑,执行效率和最初的一次性Where写法持平
新手友好的简洁写法
利用C#空条件运算符压缩判断逻辑,代码可读性更强:
itemBought = m_ItemList .Where(go => go.GetComponent<Cars>()?.Bought == true) .ToList();
写法注意点:
- 空条件运算符
?.会在GetComponent<Cars>()返回null时直接终止后续属性访问,完全不会触发空引用 - 由于
Bought是bool值类型,?.Bought最终返回的是可空bool类型,必须显式和true做等值判断,否则会出现类型不匹配的编译报错
避坑提醒
- 不要为了压缩代码把同一个
GetComponent调用散落到多个判断分支里,哪怕逻辑通顺,重复的组件查找也会在列表元素较多时积累明显的性能损耗 - 只要列表中混有不同挂载类型的GameObject,就必须在访问组件属性前增加非空判断,不要依赖"组件必然存在"的假设
内容的提问来源于stack exchange,提问作者user15199268
相关产品推荐
相关产品推荐

