当前位置: 首页 > news >正文

详细解析 Prism 模块化(Modularity)核心组件的代码

下面详细解析 Prism 模块化(Modularity)核心组件的代码。Prism 的模块化允许将应用程序拆分为独立的、可组合的模块(Module),每个模块可以独立开发、测试、部署和按需加载。给出的代码实现了模块元数据存储、模块目录扩展、模块初始化和模块管理器等关键部分。


一、整体架构概览

Prism 模块化涉及以下角色:

  • IModule:模块的接口,包含RegisterTypes(注册服务)和OnInitialized(初始化逻辑)方法。
  • ModuleInfo:描述模块的元数据(名称、类型、依赖、初始化模式、状态等)。
  • IModuleCatalog:存储和管理ModuleInfo的集合,支持依赖关系解析。
  • IModuleInitializer:负责创建模块实例并调用其生命周期方法。
  • IModuleManager:协调模块的加载、依赖解析和初始化过程。
  • IModuleTypeLoader:负责从远程位置下载模块程序集(用于动态加载)。

以下代码实现了ModuleInfo、目录扩展方法、ModuleInitializerModuleManager


二、ModuleInfo 类

publicpartialclassModuleInfo:IModuleInfo

作用

存储一个模块的元数据信息,相当于模块的“描述符”。它会被添加到IModuleCatalog中,供ModuleManager使用。

属性

属性说明
ModuleName模块的唯一名称。
ModuleType模块类型(IModule实现类)的程序集限定名称(AssemblyQualifiedName)。
DependsOn当前模块依赖的其他模块的名称集合(ModuleName)。
InitializationMode枚举值:WhenAvailable(应用启动时加载)或OnDemand(按需加载)。
Ref模块程序集的位置(如文件路径或 URL),用于动态下载。
State模块当前状态:NotStartedLoadingTypesReadyForInitializationInitializingInitialized

构造函数

提供多个重载,方便创建ModuleInfo

  • 空构造(主要用于序列化/XAML)。
  • 指定名称、类型和依赖数组。
  • 直接传入模块Type,自动提取名称和程序集限定名。
  • 支持指定初始化模式。

设计要点

  • DependsOnCollection<string>,允许 XAML 绑定和修改。
  • 实现了IModuleInfo接口,以便其他组件(如IModuleCatalog)只依赖接口而非具体类。

三、IModuleCatalogExtensions 静态类

提供一系列扩展方法,简化向IModuleCatalog添加模块的过程。

典型方法示例

publicstaticIModuleCatalogAddModule<T>(thisIModuleCatalogcatalog,InitializationModemode=InitializationMode.WhenAvailable,paramsstring[]dependsOn)whereT:IModule
  • 作用:通过泛型类型T添加模块。自动使用typeof(T).Name作为模块名称,typeof(T).AssemblyQualifiedName作为类型。
  • 其他重载允许自定义模块名称、初始化模式、依赖项,以及程序集引用位置(refValue,用于动态加载)。

分组支持

publicstaticIModuleCatalogAddGroup(thisIModuleCatalogcatalog,InitializationModeinitializationMode,stringrefValue,paramsModuleInfo[]moduleInfos)
  • 作用:添加一个模块组(ModuleInfoGroup)。如果目录实现了IModuleGroupsCatalog,则可以批量添加模块,并共享相同的RefInitializationMode
  • 这对从同一位置下载多个模块的场景非常有用(例如插件目录)。

设计优点

  • 类型安全,避免字符串拼写错误。
  • 保持IModuleCatalog接口简洁,将特定便捷方法放在扩展中。
  • 支持链式调用:catalog.AddModule<MyModule>().AddModule<OtherModule>()

四、ModuleInitializer 类

publicclassModuleInitializer:IModuleInitializer

职责

  • 根据ModuleInfo创建模块实例。
  • 调用模块的RegisterTypesOnInitialized方法。
  • 处理初始化过程中的异常。

核心方法

Initialize(IModuleInfo moduleInfo)
publicvoidInitialize(IModuleInfomoduleInfo){IModulemoduleInstance=null;try{moduleInstance=CreateModule(moduleInfo);if(moduleInstance!=null){moduleInstance.RegisterTypes(_containerExtension);moduleInstance.OnInitialized(_containerExtension);}}catch(Exceptionex){HandleModuleInitializationError(moduleInfo,moduleInstance?.GetType().Assembly.FullName,ex);}}
  • 先通过CreateModule解析模块实例。
  • 然后依次调用RegisterTypes(注册模块内的服务到容器)和OnInitialized(执行初始化逻辑,如导航注册、事件订阅)。
  • 捕获任何异常并调用HandleModuleInitializationError包装为ModuleInitializeException抛出。
CreateModule
protectedvirtualIModuleCreateModule(stringtypeName){TypemoduleType=Type.GetType(typeName);if(moduleType==null)thrownewModuleInitializeException(...);return(IModule)_containerExtension.Resolve(moduleType);}
  • 使用Type.GetType解析类型(如果程序集已加载)。
  • 通过容器解析实例,这允许模块的构造函数有依赖项(由容器自动注入)。

设计优点

  • 可重写CreateModuleHandleModuleInitializationError,支持自定义创建逻辑(如从非标准位置加载)和错误处理。
  • 依赖注入容器被用于创建模块,保证了模块本身也能享受 DI 的好处。

五、ModuleManager 类

publicpartialclassModuleManager:IModuleManager,IDisposable

职责

  • 管理模块的整个生命周期:从目录读取模块 → 处理依赖 → 触发下载(若需要)→ 初始化模块。
  • 支持按需加载(LoadModule)。
  • 提供进度和完成事件(ModuleDownloadProgressChangedLoadModuleCompleted)。

依赖

  • IModuleInitializer:用于初始化模块。
  • IModuleCatalog:提供模块列表和依赖关系。
  • IModuleTypeLoader集合:实际执行程序集下载的类型加载器(由派生类或容器提供,代码中ModuleTypeLoaders属性未显示,但通过GetTypeLoaderForModule使用)。

核心流程

1. 应用启动:Run()
publicvoidRun(){ModuleCatalog.Initialize();LoadModulesWhenAvailable();}
  • 调用目录的Initialize(允许目录延迟加载,如从配置文件读取)。
  • 加载所有初始化模式为WhenAvailable的模块。
2. 加载就绪模块:LoadModulesWhenAvailableLoadModuleTypesLoadModulesThatAreReadyForLoad
  • LoadModuleTypes遍历所有WhenAvailable模块及其依赖:
    • 若模块状态为NotStarted,检查是否需要检索(ModuleNeedsRetrieval):如果Type.GetType返回null(程序集未加载),则调用BeginRetrievingModule启动下载;否则标记为ReadyForInitialization
  • LoadModulesThatAreReadyForLoad循环处理:
    • 从目录中找到所有状态为ReadyForInitialization且依赖都已初始化(AreDependenciesLoaded)的模块。
    • 将状态改为Initializing,调用InitializeModule,然后继续循环直到没有可初始化的模块。
    • 这保证了依赖顺序:只有当一个模块的所有依赖模块都已Initialized后,它才会被初始化。
3. 按需加载:LoadModule(string moduleName)
  • 根据模块名称找到对应的ModuleInfo
  • 调用CompleteListWithDependencies(目录扩展方法)获取该模块及其所有依赖(递归)。
  • 然后调用LoadModuleTypes(与上面相同流程,会触发下载和初始化)。
4. 动态下载模块:BeginRetrievingModule
  • 通过GetTypeLoaderForModule找到能处理该模块的IModuleTypeLoader
  • 设置状态为LoadingTypes
  • 订阅加载器的LoadModuleCompletedModuleDownloadProgressChanged事件。
  • 调用moduleTypeLoader.LoadModuleType(moduleInfo)开始异步下载。
5. 下载完成回调:IModuleTypeLoader_LoadModuleCompleted
  • 若无错误,将模块状态改为ReadyForInitialization,然后调用LoadModulesThatAreReadyForLoad()继续初始化。
  • 若有错误,触发LoadModuleCompleted事件,如果错误未被处理(e.IsErrorHandled == false),则调用HandleModuleTypeLoadingError抛出异常。
6. 初始化模块:InitializeModule
  • 状态必须为Initializing
  • 调用moduleInitializer.Initialize(moduleInfo)
  • 状态改为Initialized,触发LoadModuleCompleted事件。

依赖检查:AreDependenciesLoaded

  • 通过ModuleCatalog.GetDependentModules获取当前模块依赖的模块列表。
  • 检查这些依赖是否都处于Initialized状态。

类型加载器选择:GetTypeLoaderForModule

  • 遍历ModuleTypeLoaders集合(通常由派生类或模块目录提供),找到第一个能加载该模块的加载器。
  • 如果找不到,抛出ModuleTypeLoaderNotFoundException

资源释放:Dispose

  • 遍历所有IModuleTypeLoader,若其实现了IDisposable,则释放。

事件

  • ModuleDownloadProgressChanged:透传加载器的进度事件。
  • LoadModuleCompleted:模块加载完成(成功或失败)时触发。

六、模块化完整工作流(总结)

  1. 模块注册:通过IModuleCatalog(通常在 App.xaml.cs 或启动代码中)添加模块,可以使用扩展方法AddModule<T>AddGroup
  2. 应用启动ModuleManager.Run()被调用(通常在 PrismApplication 内部)。
  3. 加载可用模块:查找所有InitializationMode.WhenAvailable的模块及其依赖。
  4. 动态加载:对于程序集未加载的模块,使用IModuleTypeLoader下载程序集(例如从网络或本地文件系统)。
  5. 依赖顺序初始化:等待所有依赖模块初始化完成后,才初始化当前模块。
  6. 模块初始化ModuleInitializer创建模块实例,调用RegisterTypesOnInitialized
  7. 按需加载:任何代码调用moduleManager.LoadModule("ModuleName"),将触发该模块及其依赖的下载和初始化。

七、设计模式与原则体现

  • 依赖倒置ModuleManager依赖IModuleCatalogIModuleInitializerIModuleTypeLoader等抽象,而非具体实现。
  • 单一职责ModuleInfo仅存储元数据;ModuleInitializer只负责创建和调用模块;ModuleManager协调流程。
  • 开闭原则:通过扩展方法为IModuleCatalog添加功能,无需修改原始接口;ModuleManager的可重写方法(如HandleModuleTypeLoadingError)允许子类扩展行为。
  • 观察者模式:通过事件LoadModuleCompletedModuleDownloadProgressChanged通知进度和结果。
  • 策略模式IModuleTypeLoader定义了不同加载策略(如从文件、从网络)的统一接口,ModuleManager根据模块信息选择合适的策略。
  • 组合模式ModuleInfoGroup(代码未完整给出,但在扩展中引用)允许将一组模块作为一个组来处理。

八、注意事项

  • 代码中的ModuleTypeLoaders集合未在当前文件中定义,通常由派生类(如ModuleManager的子类)或通过容器注入提供。
  • CompleteListWithDependenciesIModuleCatalog的扩展方法,需要手动实现或由框架提供(它递归收集模块及其所有依赖)。
  • 模块的RegisterTypes通常用于向容器注册模块内的服务(如视图、服务接口),而OnInitialized用于执行启动后逻辑(如注册导航、订阅事件)。
  • 整个设计支持后台下载按需加载,适用于大型应用或插件化架构。

通过以上组件,Prism 提供了一个灵活、强大的模块化框架,让开发者能够轻松构建可扩展、可维护的 Xamarin.Forms / MAUI 应用程序。

http://www.cnnetsun.cn/news/2658032.html

相关文章:

  • 3分钟掌握:网盘下载加速神器终极指南
  • 突破游戏窗口限制:SRWE窗口分辨率控制的三大技术优势与实践指南
  • 网站后门爆破与提权 | 网络安全教程 渗透实战案例详解
  • 从电路设计到生活创意:四步法打造智能硬件原型
  • 2026年靠谱一键生成论文工具全攻略(含详细使用步骤)
  • 从iPhone指纹到汽车芯片:聊聊Arm Trustzone技术这十几年是怎么保护我们数据的
  • 在CentOS 7上从零部署Discovery Studio 2019:一个生物信息学新手的踩坑与填坑实录
  • Simple Video Download Helper:让网页视频下载变得如此简单的终极指南
  • A/B测试失效的真相(92%团队仍在用传统方法做AI时代实验)
  • 3步搞定B站视频解析:bilibili-parse开源工具完整指南
  • SR锁存器原理与Proteus仿真实践:数字电路记忆单元入门
  • 基于BioAmp EXG Pill与Arduino搭建高精度心电监测系统
  • React技术周刊 2026年第19周
  • 告别32位限制!手把手教你为VirtualBox虚拟机‘解锁’64位系统安装权限(AMD/Intel CPU通用)
  • SketchUp建模效率翻倍:FlexTools与3dWindow插件保姆级安装与核心功能对比(2024版)
  • 树莓派Pico 2 W与OV2640摄像头实现离线图像采集与存储方案
  • 终极宝可梦随机化体验:让每一款经典游戏都成为全新冒险
  • 618 手机集体降价!
  • 从CentOS迁移到EulerOS:一个后端开发者的实战配置笔记(含Docker环境搭建)
  • 无限约束控制屏障函数:理论、算法与工程实践
  • 如何快速使用Markdown实时预览工具:面向初学者的完整指南
  • 基于XIAO M0与3D打印的巨型SNES手柄DIY全流程解析
  • 告别sc.exe!用nssm把任意exe或bat脚本注册成Windows服务的保姆级教程
  • 别再只用理想气体了!Fluent里这个隐藏的NIST真实气体模型,让你的CFD结果更靠谱
  • 深度解析R3nzSkin国服特供版:揭秘英雄联盟免费换肤技术
  • 终极指南:5个简单技巧用Ice实现macOS菜单栏清爽管理
  • AI Agent在高端服务业的应用:个性化礼宾与客户体验管理
  • [特殊字符] 论文写作急诊室:书匠策AI到底给你开了什么“处方“?
  • 基于树莓派与L293D的智能风扇网页控制项目全解析
  • AI训练数据脱敏失效真相,深度拆解92%团队忽略的元数据泄漏陷阱