You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:54:53