从存多类型List的ArrayList取变量的实现是否合理?求优化方案
优化对象映射表的实现方案
你的这个通过ID访问各类对象的思路是合理的,但当前用ArrayList的实现方式存在不少隐患,甚至有一个隐藏的运行时bug,咱们来一步步拆解并给出更优的方案:
当前实现的核心问题
- 弱类型转换不安全:
ArrayList存储的是object类型,每次访问都需要强制转换,不仅麻烦,还容易因为枚举顺序和列表顺序不匹配导致访问错误的列表(比如哪天你调整了ComponentType的枚举顺序,但忘了同步Map里的列表顺序,直接就会出问题)。 - 存在无法运行的转换bug:你代码里的
(List<object>)(ComponentMap.Map[(byte)type])会抛出InvalidCastException——因为List<T>是不变泛型类型,List<World>不能直接转换成List<object>,哪怕World是引用类型也不行。你只能转换成非泛型的IList来用索引访问,但那样还是没有类型检查。 - 无编译时校验:所有类型检查都要等到运行时才能发现,开发阶段很难提前排查问题。
更优的解决方案
方案一:强类型泛型方法+枚举匹配(最直观)
保留你原来的各个强类型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
相关产品推荐
相关产品推荐

