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

从存多类型List的ArrayList取变量的实现是否合理?求优化方案

优化对象映射表的实现方案

你的这个通过ID访问各类对象的思路是合理的,但当前用ArrayList的实现方式存在不少隐患,甚至有一个隐藏的运行时bug,咱们来一步步拆解并给出更优的方案:

当前实现的核心问题

  1. 弱类型转换不安全:ArrayList存储的是object类型,每次访问都需要强制转换,不仅麻烦,还容易因为枚举顺序和列表顺序不匹配导致访问错误的列表(比如哪天你调整了ComponentType的枚举顺序,但忘了同步Map里的列表顺序,直接就会出问题)。
  2. 存在无法运行的转换bug:你代码里的(List<object>)(ComponentMap.Map[(byte)type])会抛出InvalidCastException——因为List<T>是不变泛型类型,List<World>不能直接转换成List<object>,哪怕World是引用类型也不行。你只能转换成非泛型的IList来用索引访问,但那样还是没有类型检查。
  3. 无编译时校验:所有类型检查都要等到运行时才能发现,开发阶段很难提前排查问题。

更优的解决方案

方案一:强类型泛型方法+枚举匹配(最直观)

保留你原来的各个强类型List<T>,但去掉ArrayList,改用泛型方法或枚举匹配的方式来安全获取对应列表:

public enum ComponentType : byte { Effect, Building, City, Region, Country, World }

public static class ComponentMap {
    // 保留原有的强类型列表,方便直接访问
    public static List<World> Worlds = new List<World>();
    public static List<Country> Countries = new List<Country>();
    public static List<Region> Regions = new List<Region>();
    public static List<City> Cities = new List<City>();
    public static List<Building> Buildings = new List<Building>();
    public static List<Effect> Effects = new List<Effect>();

    // 根据ComponentType获取对应列表的强类型方法
    public static IList GetList(ComponentType type) => type switch {
        ComponentType.Effect => Effects,
        ComponentType.Building => Buildings,
        ComponentType.City => Cities,
        ComponentType.Region => Regions,
        ComponentType.Country => Countries,
        ComponentType.World => Worlds,
        _ => throw new ArgumentOutOfRangeException(nameof(type), "未知的组件类型")
    };

    // 额外提供按类型获取列表的泛型方法,方便强类型操作
    public static List<T> GetList<T>() where T : class => typeof(T) switch {
        Type t when t == typeof(Effect) => Effects as List<T>,
        Type t when t == typeof(Building) => Buildings as List<T>,
        Type t when t == typeof(City) => Cities as List<T>,
        Type t when t == typeof(Region) => Regions as List<T>,
        Type t when t == typeof(Country) => Countries as List<T>,
        Type t when t == typeof(World) => Worlds as List<T>,
        _ => throw new ArgumentException($"未找到对应类型 {typeof(T)} 的列表")
    };
}

然后你的CheckExist方法可以改成安全的版本:

private bool CheckExist(ComponentType type, ushort compId) {
    var list = ComponentMap.GetList(type);
    // 先检查索引是否在有效范围内,避免越界异常
    if (compId >= (ushort)list.Count) return false;
    return list[compId] != null;
}

这个方案的好处:

  • 完全避免了不安全的类型转换
  • 枚举和列表的映射关系清晰,不容易出错
  • 支持两种获取列表的方式,兼顾灵活性和强类型安全
  • 可以提前处理索引越界的情况,更健壮

方案二:字典映射(更灵活,适合扩展)

如果后续可能新增更多组件类型,用Dictionary来管理ComponentType和列表的映射会更灵活,避免每次新增类型都要修改switch语句:

public static class ComponentMap {
    // 用字典集中管理类型与列表的映射
    private static readonly Dictionary<ComponentType, IList> _componentLists = new() {
        { ComponentType.Effect, new List<Effect>() },
        { ComponentType.Building, new List<Building>() },
        { ComponentType.City, new List<City>() },
        { ComponentType.Region, new List<Region>() },
        { ComponentType.Country, new List<Country>() },
        { ComponentType.World, new List<World>() }
    };

    // 对外暴露获取列表的方法
    public static bool TryGetList(ComponentType type, out IList list) => 
        _componentLists.TryGetValue(type, out list);

    public static IList GetList(ComponentType type) {
        if (_componentLists.TryGetValue(type, out var list)) return list;
        throw new ArgumentOutOfRangeException(nameof(type), "未知的组件类型");
    }

    // 保留原有的属性访问方式,兼容旧代码
    public static List<Effect> Effects => (List<Effect>)GetList(ComponentType.Effect);
    public static List<Building> Buildings => (List<Building>)GetList(ComponentType.Building);
    // ... 其他属性同理
}

这个方案的优势是扩展性更好,新增组件类型时只需要在字典里添加一行即可,不需要修改大量switch分支。

总结

放弃ArrayList的弱类型实现是必须的,上面两种方案都能解决你当前的问题,同时提升代码的安全性和可维护性。如果组件类型相对固定,方案一更直观;如果后续会频繁新增类型,方案二更灵活。

内容的提问来源于stack exchange,提问作者Cotur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:34:14