Unity中C#不使用dynamic关键字,如何动态返回不同子类实例?
解决方案
针对你的需求,推荐使用泛型方法+类型-字典映射表的方案,既避免dynamic的性能损耗,又能通过单一方法获取指定类型的子类实例,扩展性也强。
步骤1:优化字典初始化与类型映射
首先把各个子类的List转成Dictionary(利用ToDictionary快速构建),同时维护一个Type到对应字典的映射表,方便后续根据类型快速定位字典:
using System.Collections.Generic; using System.Linq; using UnityEngine; public class ItemDatabase : MonoBehaviour { private static Dictionary<string, Item> items; public static Dictionary<string, Item> Items => items; private static Dictionary<string, Tool> tools; public static Dictionary<string, Tool> Tools => tools; private static Dictionary<string, Weapon> weapons; public static Dictionary<string, Weapon> Weapons => weapons; [SerializeField] private List<Item> itemsDatabase = new List<Item>(); [SerializeField] private List<Tool> toolsDatabase = new List<Tool>(); [SerializeField] private List<Weapon> weaponsDatabase = new List<Weapon>(); // 类型到对应字典的映射表 private Dictionary<Type, object> _typeToDictionary; void Awake() { // 从List构建Dictionary(假设每个Item的name作为Key) items = itemsDatabase.ToDictionary(item => item.name); tools = toolsDatabase.ToDictionary(tool => tool.name); weapons = weaponsDatabase.ToDictionary(weapon => weapon.name); // 初始化类型映射表 _typeToDictionary = new Dictionary<Type, object> { { typeof(Item), items }, { typeof(Tool), tools }, { typeof(Weapon), weapons } // 新增Food等子类时,只需添加一行:{ typeof(Food), foods } }; } }
步骤2:实现泛型获取方法
添加一个泛型方法,通过指定类型T(必须是Item的子类),从对应字典中查找实例,全程避免dynamic,性能无损耗:
public T GetItem<T>(string itemName) where T : Item { // 根据类型找到对应的字典 if (_typeToDictionary.TryGetValue(typeof(T), out var dictObj) && dictObj is Dictionary<string, T> targetDict) { // 从字典中查找目标实例 if (targetDict.TryGetValue(itemName, out var result)) { return result; } } // 找不到时的处理:ScriptableObject不能直接new,返回null并打印警告 Debug.LogWarning($"未找到名为{itemName}的{typeof(T).Name}实例"); return null; }
调用方式
使用时只需指定目标类型,直接获取强类型实例,无需额外类型转换:
// 获取Tool类型实例 Tool axe = GetItem<Tool>("IronAxe"); // 获取Weapon类型实例 Weapon sword = GetItem<Weapon>("SteelSword"); // 获取基类Item实例 Item anyItem = GetItem<Item>("Apple");
关键优势
- 性能高效:全程使用字典的
TryGetValue(O(1)查找),无dynamic的性能开销,也无需遍历所有字典。 - 扩展性强:新增子类(如Food)时,只需在类型映射表中添加一行对应关系,无需修改获取方法。
- 类型安全:编译时即可检查类型正确性,避免运行时类型转换错误。
注意事项
- 确保所有Item实例的
name字段唯一,避免字典Key冲突。 - ScriptableObject不能通过
new创建实例,找不到时建议返回null而非手动实例化,避免不符合Unity的资源管理逻辑。
内容的提问来源于stack exchange,提问作者Tirais
相关产品推荐
相关产品推荐

