Unity中PageManager的GetPage方法如何实现动态返回对应子类类型?
问题:Unity页面管理器GetPage方法的优雅实现方案
本人编程经验不足2年,C#开发经验更短,目前在做一个Unity移动端项目。项目包含多个页面,每个页面都挂载继承自PageIDSystem(继承自MonoBehaviour)的PageBehavior脚本。PageIDSystem简化代码如下:
public abstract class PageIDSystem : MonoBehaviour { public enum eDisplayPage { Page1, Page2, //and so on } public eDisplayPage PageID; }
所有继承该类的页面都会设置PageID属性。为了集中管理页面切换,我实现了单例PageManager类,包含GetPage、GetCurrentPage等方法。现在希望GetPage(eDisplayPage pageType)方法能返回对应PageIDSystem子类的实例,理想用法如下:
PageManager.Instance.GetPage(eDisplayPage.Page1).SomeMethodDefinedInPage1(); PageManager.Instance.GetPage(eDisplayPage.Page2).SomeOtherIdkInitializeParam("init");
我尝试过两种方案:
- 用
dynamic作为返回类型,结合Convert.ChangeType转换,但Unity不支持运行时推导的dynamic; - 用泛型实现,代码如下:
public T GetPage<T>(eDisplayPage ID) where T : PageIDSystem { // find page corresponding to the input ID return page as T; }
该方案可行,但需要同时传入泛型类型和枚举参数,感觉冗余。想请教是否有更优雅的实现方式。
解决方案
方案1:枚举-类型映射表+重载方法
提前维护枚举值与页面子类的映射关系,通过重载方法实现两种调用方式,避免冗余参数。
首先在PageManager中初始化映射字典:
private Dictionary<PageIDSystem.eDisplayPage, Type> _pageTypeMap; private void Awake() { _pageTypeMap = new Dictionary<PageIDSystem.eDisplayPage, Type> { { PageIDSystem.eDisplayPage.Page1, typeof(Page1Behavior) }, { PageIDSystem.eDisplayPage.Page2, typeof(Page2Behavior) }, // 补充其他页面的映射 }; }
然后实现两个重载的GetPage方法:
// 按枚举获取基础类型实例 public PageIDSystem GetPage(PageIDSystem.eDisplayPage pageType) { // 替换为你实际的页面查找逻辑,比如从缓存列表中匹配PageID return FindObjectsOfType<PageIDSystem>().First(p => p.PageID == pageType); } // 泛型重载,通过类型自动匹配枚举 public T GetPage<T>() where T : PageIDSystem { var targetEnum = _pageTypeMap.First(kv => kv.Value == typeof(T)).Key; return GetPage(targetEnum) as T; }
调用方式可选:
// 方式1:接近理想用法,显式转换类型 ((Page1Behavior)PageManager.Instance.GetPage(eDisplayPage.Page1)).SomeMethodDefinedInPage1(); // 方式2:泛型调用,无需传枚举 PageManager.Instance.GetPage<Page1Behavior>().SomeMethodDefinedInPage1();
嫌显式转换麻烦的话,可加一个扩展方法简化:
public static class PageExtensions { public static T As<T>(this PageIDSystem page) where T : PageIDSystem { return page as T; } }
这样理想用法可写成:
PageManager.Instance.GetPage(eDisplayPage.Page1).As<Page1Behavior>().SomeMethodDefinedInPage1();
方案2:枚举特性标记+反射
给枚举值标记对应页面类型,通过反射自动获取类型,无需手动维护字典。
先定义特性类:
[AttributeUsage(AttributeTargets.Field)] public class PageTypeAttribute : Attribute { public Type PageType { get; } public PageTypeAttribute(Type pageType) { PageType = pageType; } }
修改枚举添加标记:
public enum eDisplayPage { [PageType(typeof(Page1Behavior))] Page1, [PageType(typeof(Page2Behavior))] Page2, // 其他页面 }
在PageManager中添加类型解析方法:
private Type GetPageTypeFromEnum(PageIDSystem.eDisplayPage pageType) { var fieldInfo = pageType.GetType().GetField(pageType.ToString()); var attribute = fieldInfo.GetCustomAttribute<PageTypeAttribute>(); return attribute?.PageType; }
后续GetPage方法可基于此实现,逻辑和方案1一致,但扩展性更强,新增页面只需给枚举加特性即可。
方案3:编译时模式匹配
如果页面数量少,可直接用switch模式匹配硬编码,省去映射逻辑:
public T GetPage<T>(PageIDSystem.eDisplayPage pageType) where T : PageIDSystem { var page = FindObjectsOfType<PageIDSystem>().First(p => p.PageID == pageType); return page switch { Page1Behavior p1 => p1 as T, Page2Behavior p2 => p2 as T, _ => null }; }
这种方式适合小型项目,缺点是新增页面需要修改switch分支。
内容的提问来源于stack exchange,提问作者Jonghun Lee
相关产品推荐
相关产品推荐

