0

0

C# Avalonia如何实现一个插件系统 Avalonia MEF/DI插件

煙雲

煙雲

发布时间:2026-01-01 10:59:02

|

978人浏览过

|

来源于php中文网

原创

推荐在Avalonia中使用Microsoft.Extensions.DependencyInjection结合AssemblyLoadContext实现插件系统:定义IPlugin等契约接口,通过隔离的AssemblyLoadContext动态加载插件DLL,插件向宿主IServiceCollection注册服务,宿主聚合INavigationProvider菜单项与IViewComponent视图并解耦通信。

c# avalonia如何实现一个插件系统 avalonia mef/di插件

在 Avalonia 中实现插件系统,推荐使用 Microsoft.Extensions.DependencyInjection(DI) 结合 MEF(Managed Extensibility Framework) 或纯 DI 方式动态加载插件。Avalonia 本身不内置插件机制,但可借助 .NET 的模块化能力(如 AssemblyLoadContext、AssemblyLoadEventArgs、接口抽象 + 运行时反射)构建松耦合、热插拔的插件架构。

定义统一插件接口与契约

所有插件必须实现约定接口,这是解耦核心。建议放在独立类库(如 MyApp.Plugins.Contracts)中供宿主和插件共同引用:

  • IPlugin:基础生命周期(Initialize() / Shutdown()
  • INavigationProvider:提供菜单项或导航入口(返回 MenuItemRoute
  • IViewComponent:可被 ContentControl 动态渲染的 Avalonia 控件(继承自 Control
  • 避免在接口中引用 Avalonia 程序集(如 Avalonia.Controls.Button),改用抽象类型或数据模型

插件发现与动态加载(基于 AssemblyLoadContext)

不依赖 MEF 的轻量方案(更可控、兼容 .NET 6+):

  • 插件以 .dll 形式存放于 Plugins/ 目录,命名规范如 MyPlugin.dll
  • 创建隔离的 AssemblyLoadContext 防止类型冲突:
var pluginContext = new AssemblyLoadContext(isCollectible: true);
var assembly = pluginContext.LoadFromAssemblyPath(pluginPath);
  • 遍历 assembly.GetTypes(),筛选实现 IPlugin 的类型,用 Activator.CreateInstance 创建实例
  • 调用 plugin.Initialize(services),将宿主的 IServiceCollection 传入,让插件注册自身服务(如 services.AddSingleton()

宿主 DI 容器集成插件服务

AppBuilder 构建阶段注入插件:

Codiga
Codiga

可自定义的静态代码分析检测工具

下载
  • 先构建基础 IServiceCollection(含 Avalonia 默认服务)
  • 扫描并加载插件,执行其 Initialize(IServiceCollection)
  • 完成所有插件注册后,调用 BuildServiceProvider()
  • 关键点:插件内部应只注册服务,**不调用 BuildServiceProvider**,避免容器嵌套

示例片段:

var services = new ServiceCollection();
// 注册宿主服务...
RegisterHostServices(services);

// 加载插件
foreach (var pluginPath in GetPluginPaths())
{
    var plugin = LoadPlugin(pluginPath);
    plugin.Initialize(services); // 插件向 services 添加自己的类型
}

var app = BuildAvaloniaApp()
    .UsePlatformDetect()
    .SetupWithLifetime(lifetime);
app.StartWithClassicDesktopLifetime(args, ShutdownMode.OnMainWindowClose);

运行时 UI 扩展(菜单/视图/命令)

插件通过接口向宿主“声明能力”,宿主负责聚合与呈现:

  • 插件实现 INavigationProvider.GetMenuItems() → 宿主收集所有 MenuItem 并添加到主菜单
  • 插件实现 IViewComponent.CreateView() → 宿主用 绑定渲染
  • 命令可绑定到 ICommand 属性,由插件提供 ViewModel 实现,宿主仅负责触发
  • 避免直接在插件中操作宿主窗口(如 Application.Current.MainWindow),改用事件或消息总线(如 WeakEventCommunityToolkit.Mvvm.Messaging)通信

不复杂但容易忽略:确保插件 DLL 不包含重复依赖(如 Avalonia.*),全部由宿主提供;发布时将插件目录设为 CopyToOutputDirectory;调试阶段可用 AssemblyResolve 事件辅助定位加载失败原因。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1017

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

62

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

400

2025.12.29

vsd文件打开方法
vsd文件打开方法

vsd文件打开方法有使用Microsoft Visio软件、使用Microsoft Visio查看器、转换为其他格式等。想了解更多vsd文件相关内容,可以阅读本专题下面的文章。

479

2023.10.30

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

34

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

14

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

33

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

18

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

12

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 45.9万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号