反射库,类型增加As扩展,是否能够转为指定基类
大石头 authored at 2017-04-22 22:42:43
6.01 KiB
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NewLife.Log;
using NewLife.Reflection;

namespace NewLife.Model
{
    /// <summary>通用插件接口</summary>
    /// <remarks>
    /// 为了方便构建一个简单通用的插件系统,先规定如下:
    /// 1,负责加载插件的宿主,在加载插件后会进行插件实例化,此时可在插件构造函数中做一些事情,但不应该开始业务处理,因为宿主的准备工作可能尚未完成
    /// 2,宿主一切准备就绪后,会顺序调用插件的Init方法,并将宿主标识传入,插件通过标识区分是否自己的目标宿主。插件的Init应尽快完成。
    /// 3,如果插件实现了<see cref="IDisposable"/>接口,宿主最后会清理资源。
    /// </remarks>
    public interface IPlugin
    {
        /// <summary>初始化</summary>
        /// <param name="identity">插件宿主标识</param>
        /// <param name="provider">服务提供者</param>
        /// <returns>返回初始化是否成功。如果当前宿主不是所期待的宿主,这里返回false</returns>
        Boolean Init(String identity, IServiceProvider provider);
    }

    /// <summary>插件特性。用于判断某个插件实现类是否支持某个宿主</summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class PluginAttribute : Attribute
    {
        private String _Identity;
        /// <summary>插件宿主标识</summary>
        public String Identity { get { return _Identity; } set { _Identity = value; } }

        /// <summary>实例化</summary>
        /// <param name="identity"></param>
        public PluginAttribute(String identity) { Identity = identity; }
    }

    /// <summary>插件管理器</summary>
    public class PluginManager : DisposeBase, IServiceProvider
    {
        #region 属性
        private String _Identity;
        /// <summary>宿主标识,用于供插件区分不同宿主</summary>
        public String Identity { get { return _Identity; } set { _Identity = value; } }

        private IServiceProvider _Provider;
        /// <summary>宿主服务提供者</summary>
        public IServiceProvider Provider { get { return _Provider; } set { _Provider = value; } }

        private List<IPlugin> _Plugins;
        /// <summary>插件集合</summary>
        public List<IPlugin> Plugins { get { return _Plugins ?? (_Plugins = new List<IPlugin>()); } }

        private ILog _Log = XTrace.Log;
        /// <summary>日志提供者</summary>
        public ILog Log { get { return _Log; } set { _Log = value; } }
        #endregion

        #region 构造
        /// <summary>实例化一个插件管理器</summary>
        public PluginManager() { }

        /// <summary>使用宿主对象实例化一个插件管理器</summary>
        /// <param name="host"></param>
        public PluginManager(Object host)
        {
            if (host != null)
            {
                Identity = host.ToString();
                Provider = host as IServiceProvider;
            }
        }

        /// <summary>子类重载实现资源释放逻辑时必须首先调用基类方法</summary>
        /// <param name="disposing">从Dispose调用(释放所有资源)还是析构函数调用(释放非托管资源)。
        /// 因为该方法只会被调用一次,所以该参数的意义不太大。</param>
        protected override void OnDispose(Boolean disposing)
        {
            base.OnDispose(disposing);

            if (disposing)
            {
                _Plugins.TryDispose();
                _Plugins = null;
            }
        }
        #endregion

        #region 方法
        /// <summary>加载插件。此时是加载所有插件,无法识别哪些是需要的</summary>
        public void Load()
        {
            var list = new List<IPlugin>();
            // 此时是加载所有插件,无法识别哪些是需要的
            foreach (var item in LoadPlugins())
            {
                if (item != null)
                {
                    list.Add(item.CreateInstance() as IPlugin);
                }
            }
            _Plugins = list;
        }

        IList<Type> pluginTypes;
        IEnumerable<Type> LoadPlugins()
        {
            if (pluginTypes != null) return pluginTypes;

            var list = new List<Type>();
            // 此时是加载所有插件,无法识别哪些是需要的
            foreach (var item in typeof(IPlugin).GetAllSubclasses(true))
            {
                if (item != null)
                {
                    // 如果有插件特性,并且所有特性都不支持当前宿主,则跳过
                    var atts = item.GetCustomAttributes<PluginAttribute>(true);
                    if (atts != null && atts.Any(a => a.Identity != Identity)) continue;

                    list.Add(item);
                }
            }
            return pluginTypes = list;
        }

        /// <summary>开始初始化。初始化之后,不属于当前宿主的插件将会被过滤掉</summary>
        public void Init()
        {
            var ps = Plugins;
            if (ps == null || ps.Count < 1) return;

            for (var i = ps.Count - 1; i >= 0; i--)
            {
                try
                {
                    if (!ps[i].Init(Identity, Provider)) ps.RemoveAt(i);
                }
                catch (Exception ex)
                {
                    //XTrace.WriteExceptionWhenDebug(ex);
                    Log.Debug(null, ex);

                    ps.RemoveAt(i);
                }
            }
        }
        #endregion

        #region IServiceProvider 成员
        Object IServiceProvider.GetService(Type serviceType)
        {
            if (serviceType == typeof(PluginManager)) return this;

            return Provider?.GetService(serviceType);
        }
        #endregion
    }
}