Unity中如何通过变量引用ScriptableObject动作,避免硬编码?
在C#中通过字符串变量名动态访问ScriptableObject动作的方案
以下是几种替代硬编码switch的可行方案,兼顾灵活性和扩展性:
方案1:反射实现动态属性访问
反射可以直接通过属性名字符串获取对应值,适合追求配置灵活性、调用频率不高的场景。如果需要频繁调用,建议提前缓存映射关系避免重复反射开销。
基础反射写法:
// 假设actions是自定义类实例,比如ItemActions类型 var actionsType = itemScriptableObject.actions.GetType(); // 根据属性名获取属性信息,建议缓存该对象 var actionProperty = actionsType.GetProperty(actionPicker); if (actionProperty != null) { actionSO = actionProperty.GetValue(itemScriptableObject.actions) as ScriptableObject; // 执行动作逻辑 }
缓存映射的优化写法(初始化时一次性反射所有动作):
private Dictionary<string, ScriptableObject> _actionMap; void Awake() { _actionMap = new Dictionary<string, ScriptableObject>(); var actionsType = itemScriptableObject.actions.GetType(); // 筛选出所有public的ScriptableObject类型属性 var actionProperties = actionsType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.PropertyType.IsAssignableFrom(typeof(ScriptableObject))); foreach (var prop in actionProperties) { var action = prop.GetValue(itemScriptableObject.actions) as ScriptableObject; if (action != null) { _actionMap.Add(prop.Name, action); } } } // 点击事件处理器 void OnClick() { if (_actionMap.TryGetValue(actionPicker, out var selectedAction)) { actionSO = selectedAction; // 执行动作逻辑 } }
方案2:手动维护字典映射(性能最优)
如果动作数量固定或变动不频繁,直接在初始化时手动绑定动作与字符串key,性能比反射更优,逻辑也更直观。
private Dictionary<string, ScriptableObject> _actionMap; void Awake() { _actionMap = new Dictionary<string, ScriptableObject> { {"action1", itemScriptableObject.actions.action1}, {"action2", itemScriptableObject.actions.action2}, {"action3", itemScriptableObject.actions.action3} }; } // 点击事件处理器 void OnClick() { if (_actionMap.TryGetValue(actionPicker, out var selectedAction)) { actionSO = selectedAction; // 执行动作逻辑 } }
方案3:修改数据结构(根源解决扩展性)
如果后续需要持续新增动作,建议直接调整ScriptableObject的数据结构,用可配置的键值对替代独立属性,完全摆脱对属性名的依赖。
首先修改ScriptableObject定义:
[Serializable] public class ActionEntry { public string actionKey; public ScriptableObject actionSO; } // 在你的ItemScriptableObject类中替换原有actions字段 public List<ActionEntry> actions;
然后初始化时转成字典:
private Dictionary<string, ScriptableObject> _actionMap; void Awake() { _actionMap = itemScriptableObject.actions.ToDictionary(entry => entry.actionKey, entry => entry.actionSO); }
后续新增动作只需在Inspector面板中添加ActionEntry条目,无需修改任何代码。
内容的提问来源于stack exchange,提问作者makeITwork
相关产品推荐
相关产品推荐

