C#集合初始化器与集合定义合并使用失效问题求助
问题:Unity中C#集合初始化器在字段声明时失效的原因
首先看出现问题的代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ListEX : MonoBehaviour { public List<string> sList = new List<string>() { "A", "B", "C", "D", }; void Start() { sList.Add("X"); sList.Add("Y"); string str = ""; foreach (string i in sList) { str += i; } print(str); } }
运行后输出为XY,而非预期的ABCDXY。
将初始化逻辑移到Start方法后,代码正常输出ABCDXY:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ListEX : MonoBehaviour { public List<string> sList; void Start() { sList = new List<string>() { "A", "B", "C", "D", }; sList.Add("X"); sList.Add("Y"); string str = ""; foreach (string i in sList) { str += i; } print(str); } }
核心原因:Unity的序列化机制
这不是C#语言本身的问题,而是Unity对MonoBehaviour子类公有字段的序列化行为导致的:
- 当你在MonoBehaviour子类的公有字段声明处直接初始化集合(包括使用集合初始化器),Unity的序列化系统会在对象生命周期的Awake之前(具体是在反序列化阶段)重新创建该集合的实例,覆盖你在字段声明时初始化的内容。
- 因为你没有在Inspector面板中给这个集合赋值,Unity会创建一个空的集合实例,所以
Start方法中添加的"X"和"Y"就成了集合里仅有的元素,最终输出XY。 - 而将初始化逻辑放在
Start方法中时,序列化阶段已经完成,Unity不会再干预这个集合的实例,你手动创建的带初始元素的集合会被保留,后续添加的元素也能正常生效,所以输出符合预期。
补充说明
- 不仅是
List<T>,数组、Dictionary<TKey,TValue>等可序列化集合都会遇到这个问题,只要是MonoBehaviour的公有字段,且未在Inspector中赋值,Unity就会用空实例覆盖你在字段声明时的初始化。 - 如果想要在字段声明时初始化集合且不被Unity序列化覆盖,可以给字段添加
[System.NonSerialized]属性,这样Unity的序列化系统会忽略这个字段,你的初始化代码就能正常生效。
内容的提问来源于stack exchange,提问作者SilverLawrence
相关产品推荐
相关产品推荐

