56 Star 107 Fork 57

小李 / Plugin.NET

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

Plugin.NET

Plugin.NET 目标是搞一个灵活的c#插件管理器(后面统称为管理器)。管理器使用反射(Reflect)技术,动态地加载dll类库(即插件)。在使用管理器的时候,会要求将一个abstract的类作为泛型参数传入,插件需要实现这个类的接口,而应用程序通过这个类里面的接口来调用插件。

项目目前都是下班回家后空闲时间在搞,所以进度有点慢。欢迎朋友们一起PR。 :relieved: :relieved: :relieved:

运行环境

项目使用 .net 4.0 编写,自己随便改改代码就能用到.net2.0和.netcore上。

接口定义规范

说是接口,准确来说,应该是一个虚类,即由abstract修饰的类。这个类里面,包含插件必须实现和可选实现的两类接口(方法)。其中,必须实现的接口使用abstract修饰,可选实现的方法使用virtual修饰。示例如下:

/// <summary>
/// 插件接口
/// </summary>
public abstract class PluginInterface
{
    /// <summary>
    /// 插件名称
    /// </summary>
    public abstract string Name { get; }

    /// <summary>
    /// 插件版本
    /// </summary>
    public abstract Version Version { get; }

    /// <summary>
    /// 插件描述
    /// </summary>
    public virtual string Description { get; }

    /// <summary>
    /// 加载插件后调用,使用了 abstract 修饰,所以必须实现
    /// </summary>
    public abstract void Load();

    /// <summary>
    /// 第一个功能方法,使用了 virtual 修饰,所以可选实现
    /// </summary>
    /// <returns></returns>
    public virtual string Method1()
    {
        return null;
    }

    /// <summary>
    /// 第二个功能方法,使用了 virtual 修饰,所以可选实现
    /// </summary>
    /// <param name="from"></param>
    /// <returns></returns>
    public virtual string Method2(string from)
    {
        return from;
    }
}

这里使用virtual来作为可选修饰是为了方便程序的接口升级,否则每接口有变化,插件都必须进行修改。

插件实现规范

插件所在项目需要引用接口所在的dll文件,在发布插件时不需要发布这个接口dll,但是如果有其它依赖的dll,需要一起发布。管理器会查找插件的类继承,插件中继承接口的类会通过无参数构造创建实例,然后交给程序使用,所以在实现插件时,必须提供一下无参的构造。

需要注意的是,管理器只会使用在插件中找到的第一个实现了接口的类,其它的类将被忽略

管理器使用流程

  1. 编写程序的接口类,在入口项目中引用这个接口
  2. 在程序中引用Plugin.NET.dll
  3. 初始化插件管理器
  4. 绑定插件管理器的事件,各种事件提供了丰富的插件加载数据
  5. 调用 Load 方法加载已经存在的所有插件,这个方法可以传入一个过滤器函数
  6. 如果希望插件可以热加载,那么再调用 Watch 方法,以监视插件目录是否有新的插件放进去
  7. 如果要停止热加载,那么就调用 StopWatch 以停止监视插件目录

示例

class Program
{
    static void Main(string[] args)
    {
        // 使用接口来实例化插件管理器
        // 如果要对其它接口进行插件管理,
        // 那么可以创建另一个插件管理器的实例
        var pluginManager = new PluginManager<PluginInterface>();

        // 处理插件管理器发出的事件
        pluginManager.OnAssemblyLoading += PluginManager_OnAssemblyLoading;
        pluginManager.OnAssemblyLoaded += PluginManager_OnAssemblyLoaded;
        pluginManager.OnError += PluginManager_OnError;
        pluginManager.OnInstanceCreating += PluginManager_OnInstanceCreating;
        pluginManager.OnInstanceCreated += PluginManager_OnInstanceCreated;

        // 加载插件目录下的所有插件
        pluginManager.Load();

        // 开始监视新放进目录的插件
        pluginManager.Watch();


        Console.WriteLine("正在监视插件目录变动,按`Enter`退出");
        Console.ReadLine();
    }

    private static void PluginManager_OnAssemblyLoading(object sender, PluginAssemblyLoadingArgs e)
    {
        Console.WriteLine($"准备从文件\"{e.FileName}\"加载程序集");
    }

    private static void PluginManager_OnAssemblyLoaded(object sender, PluginAssemblyLoadedArgs e)
    {
        Console.WriteLine($"从文件\"{e.FileName}\"加载程序集\"{e.Assembly}\"成功");
    }

    private static void PluginManager_OnInstanceCreating(object sender, PluginInstanceCreatingArgs e)
    {
        Console.WriteLine($"准备从程序集\"{e.Assembly}\"加载类型\"{e.Class}\"");
    }

    private static void PluginManager_OnInstanceCreated(object sender, PluginInstanceCreatedArgs<PluginInterface> e)
    {
        var plugin = e.Instance;
        Console.WriteLine($"从程序集\"{e.Assembly}\"加载类型\"{e.Class}\"成功");
        Console.WriteLine($"插件名称: {plugin.Name}, 版本: {plugin.Version}");
        e.Instance.Load();
        Console.WriteLine("Method1:" + plugin.Method1());
        Console.WriteLine("Method2:" + plugin.Method2("啊呀哟"));
    }

    private static void PluginManager_OnError(object sender, PluginErrorEventArgs e)
    {
        switch (e.ErrorType)
        {
            case PluginNET.error.PluginErrorTypes.None:
                break;
            case PluginNET.error.PluginErrorTypes.InvalidDll:
                Console.WriteLine($"文件\"{e.FileName}\"不是有效有dll: {e.Exception}");
                break;
            case PluginNET.error.PluginErrorTypes.CannotLoadClassTypes:
                Console.WriteLine($"无法从文件\"{e.FileName}\"中加载类型: {e.Exception}");
                break;
            case PluginNET.error.PluginErrorTypes.ImplementionClassNotFound:
                Console.WriteLine($"在文件\"{e.FileName}\"中没有找到实现了指定接口的类");
                break;
            case PluginNET.error.PluginErrorTypes.IllegalClassDefinition:
                Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类,但是其声明不是class或声明为abstract或不是public");
                break;
            case PluginNET.error.PluginErrorTypes.DefaultConstructorNotFound:
                Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类,但未找到默认的无参构造函数");
                break;
            case PluginNET.error.PluginErrorTypes.InstanceCreateFailed:
                Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类\"{e.ClassType}\",但是创建实例时抛出了异常:{e.Exception}");
                break;
            case PluginNET.error.PluginErrorTypes.Unkown:
                Console.WriteLine("未知错误");
                break;
            default:
                break;
        }
    }
}

示例请看解决方案中的test目录,测试项目为Plugin.NETTest

The MIT License (MIT) Copyright (c) 2016 hyjiacan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

c#插件管理器 展开 收起
C#
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
C#
1
https://gitee.com/hyjiacan/Plugin.NET.git
git@gitee.com:hyjiacan/Plugin.NET.git
hyjiacan
Plugin.NET
Plugin.NET
master

搜索帮助

14c37bed 8189591 565d56ea 8189591