必须填写至少10个字的日志
nnhy 编写于 2012-07-27 18:48:21
X
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Web;
using NewLife.Collections;
#if NET4
using System.Linq;
#else
using NewLife.Linq;
#endif
using System.Runtime.InteropServices;
using NewLife.Log;

namespace NewLife.Reflection
{
    /// <summary>程序集辅助类。使用Create创建,保证每个程序集只有一个辅助类</summary>
    public class AssemblyX //: FastIndexAccessor
    {
        #region 属性
        private Assembly _Asm;
        /// <summary>程序集</summary>
        public Assembly Asm { get { return _Asm; } }

        [NonSerialized]
        private List<String> hasLoaded = new List<String>();

        private String _Name;
        /// <summary>名称</summary>
        public String Name { get { return _Name ?? (_Name = "" + Asm.GetName().Name); } }

        private String _Version;
        /// <summary>程序集版本</summary>
        public String Version { get { return _Version ?? (_Version = "" + Asm.GetName().Version); } }

        private String _Title;
        /// <summary>程序集标题</summary>
        public String Title { get { return _Title ?? (_Title = "" + Asm.GetCustomAttributeValue<AssemblyTitleAttribute, String>()); } }

        private String _FileVersion;
        /// <summary>文件版本</summary>
        public String FileVersion { get { return _FileVersion ?? (_FileVersion = "" + Asm.GetCustomAttributeValue<AssemblyFileVersionAttribute, String>()); } }

        private DateTime _Compile;
        /// <summary>编译时间</summary>
        public DateTime Compile
        {
            get
            {
                if (_Compile <= DateTime.MinValue && !hasLoaded.Contains("Compile"))
                {
                    hasLoaded.Add("Compile");

                    if (!String.IsNullOrEmpty(Version))
                    {
                        var ss = Version.Split(new Char[] { '.' });
                        var d = Convert.ToInt32(ss[2]);
                        var s = Convert.ToInt32(ss[3]);

                        var dt = new DateTime(2000, 1, 1);
                        dt = dt.AddDays(d).AddSeconds(s * 2);

                        _Compile = dt;
                    }
                }
                return _Compile;
            }
        }

        private Version _CompileVersion;
        /// <summary>编译版本</summary>
        public Version CompileVersion
        {
            get
            {
                if (_CompileVersion == null)
                {
                    var ver = Asm.GetName().Version;
                    if (ver == null) ver = new Version(1, 0);

                    var dt = Compile;
                    ver = new Version(ver.Major, ver.Minor, dt.Year, dt.Month * 100 + dt.Day);

                    _CompileVersion = ver;
                }
                return _CompileVersion;
            }
        }

        private String _Company;
        /// <summary>公司名称</summary>
        public String Company { get { return _Company ?? (_Company = "" + Asm.GetCustomAttributeValue<AssemblyCompanyAttribute, String>()); } }

        private String _Description;
        /// <summary>说明</summary>
        public String Description { get { return _Description ?? (_Description = "" + Asm.GetCustomAttributeValue<AssemblyDescriptionAttribute, String>()); } }

        /// <summary>获取包含清单的已加载文件的路径或 UNC 位置。</summary>
        public String Location { get { try { return Asm == null || Asm is _AssemblyBuilder ? null : Asm.Location; } catch { return null; } } }
        #endregion

        #region 构造
        private AssemblyX(Assembly asm) { _Asm = asm; }

        private static DictionaryCache<Assembly, AssemblyX> cache = new DictionaryCache<Assembly, AssemblyX>();
        /// <summary>创建程序集辅助对象</summary>
        /// <param name="asm"></param>
        /// <returns></returns>
        public static AssemblyX Create(Assembly asm)
        {
            if (asm == null) return null;

            return cache.GetItem(asm, key => new AssemblyX(key));
        }

        static AssemblyX()
        {
            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve);
        }

        static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
        {
            return Assembly.ReflectionOnlyLoad(args.Name);
        }
        #endregion

        #region 扩展属性
        //private IEnumerable<Type> _Types;
        /// <summary>类型集合,当前程序集的所有类型,包括私有和内嵌,非内嵌请直接调用Asm.GetTypes()</summary>
        public IEnumerable<Type> Types
        {
            get
            {
                Type[] ts = null;
                try
                {
                    ts = Asm.GetTypes();
                }
                catch (ReflectionTypeLoadException ex)
                {
                    if (ex.LoaderExceptions != null)
                    {
                        XTrace.WriteLine("加载[{0}]{1}的类型时发生个{2}错误!", this, Location, ex.LoaderExceptions.Length);
                        foreach (var le in ex.LoaderExceptions)
                        {
                            XTrace.WriteException(le);
                        }
                    }
                    ts = ex.Types;
                }
                if (ts == null || ts.Length < 1) yield break;

                // 先遍历一次ts,避免取内嵌类型带来不必要的性能损耗
                foreach (var item in ts)
                {
                    if (item != null) yield return item;
                }

                var queue = new Queue<Type>(ts);
                while (queue.Count > 0)
                {
                    var item = queue.Dequeue();
                    if (item == null) continue;

                    var ts2 = item.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
                    if (ts2 != null && ts2.Length > 0)
                    {
                        // 从下一个元素开始插入,让内嵌类紧挨着主类
                        //Int32 k = i + 1;
                        foreach (var elm in ts2)
                        {
                            //if (!list.Contains(item)) list.Insert(k++, item);
                            // Insert将会导致大量的数组复制
                            queue.Enqueue(elm);

                            yield return elm;
                        }
                    }
                }
            }
        }

        //private IEnumerable<TypeX> _TypeXs;
        /// <summary>类型集合,当前程序集的所有类型</summary>
        public IEnumerable<TypeX> TypeXs
        {
            get
            {
                foreach (Type item in Types)
                {
                    yield return TypeX.Create(item);
                }
            }
        }

        /// <summary>是否系统程序集</summary>
        public Boolean IsSystemAssembly
        {
            get
            {
                String name = Asm.FullName;
                if (name.EndsWith("PublicKeyToken=b77a5c561934e089")) return true;
                if (name.EndsWith("PublicKeyToken=b03f5f7f11d50a3a")) return true;

                return false;
            }
        }
        #endregion

        #region 静态属性
        ///// <summary>当前执行代码程序集</summary>
        //public static AssemblyX Executing { get { return AssemblyX.Create(Assembly.GetExecutingAssembly()); } }

        /// <summary>入口程序集</summary>
        public static AssemblyX Entry { get { return AssemblyX.Create(Assembly.GetEntryAssembly()); } }

        ///// <summary>调用者</summary>
        //public static AssemblyX Calling { get { return AssemblyX.Create(Assembly.GetCallingAssembly()); } }
        #endregion

        #region 获取特性
        /// <summary>获取自定义属性</summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <returns></returns>
        [Obsolete("=>Asm.GetCustomAttribute<TAttribute>")]
        public TAttribute GetCustomAttribute<TAttribute>() { return Asm.GetCustomAttribute<TAttribute>(); }

        /// <summary>获取自定义属性的值。可用于ReflectionOnly加载的程序集</summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <returns></returns>
        [Obsolete("=>Asm.GetCustomAttributeValue<TAttribute, TResult>")]
        public TResult GetCustomAttributeValue<TAttribute, TResult>()
        {
            var list = CustomAttributeData.GetCustomAttributes(Asm);
            if (list == null || list.Count < 1) return default(TResult);

            foreach (var item in list)
            {
                if (typeof(TAttribute) != item.Constructor.DeclaringType) continue;

                if (item.ConstructorArguments != null && item.ConstructorArguments.Count > 0)
                    return (TResult)item.ConstructorArguments[0].Value;
            }

            return default(TResult);
        }
        #endregion

        #region 方法
        DictionaryCache<String, Type> typeCache2 = new DictionaryCache<String, Type>();
        /// <summary>从程序集中查找指定名称的类型</summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public Type GetType(String typeName)
        {
            if (String.IsNullOrEmpty(typeName)) throw new ArgumentNullException("typeName");

            return typeCache2.GetItem(typeName, GetTypeInternal);
        }

        /// <summary>在程序集中查找类型</summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        Type GetTypeInternal(String typeName)
        {
            var type = Asm.GetType(typeName);
            if (type != null) return type;

            // 如果没有包含圆点,说明其不是FullName
            if (!typeName.Contains("."))
            {
                var types = Asm.GetTypes();
                if (types != null && types.Length > 0)
                {
                    foreach (var item in types)
                    {
                        if (item.Name == typeName) return item;
                    }
                }

                // 遍历所有类型,包括内嵌类型
                foreach (var item in TypeXs)
                {
                    if (item.Name == typeName) return item;
                }
            }

            return null;
        }
        #endregion

        #region 插件
        /// <summary>查找插件</summary>
        /// <typeparam name="TPlugin"></typeparam>
        /// <returns></returns>
        public List<Type> FindPlugins<TPlugin>() { return FindPlugins(typeof(TPlugin)); }

        private Dictionary<Type, List<Type>> _plugins = new Dictionary<Type, List<Type>>();
        /// <summary>查找插件,带缓存</summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public List<Type> FindPlugins(Type type)
        {
            // 如果type是null,则返回所有类型

            List<Type> list = null;
            if (_plugins.TryGetValue(type, out list)) return list;
            lock (_plugins)
            {
                if (_plugins.TryGetValue(type, out list)) return list;

                list = new List<Type>();
                foreach (var item in Types)
                {
                    if (TypeX.Create(item).IsPlugin(type)) list.Add(item);
                }
                if (list.Count <= 0) list = null;

                _plugins.Add(type, list);

                return list;
            }
        }

        /// <summary>查找所有非系统程序集中的所有插件</summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IEnumerable<Type> FindAllPlugins(Type type) { return FindAllPlugins(type, false); }

        /// <summary>查找所有非系统程序集中的所有插件</summary>
        /// <remarks>继承类所在的程序集会引用baseType所在的程序集,利用这一点可以做一定程度的性能优化。</remarks>
        /// <param name="baseType"></param>
        /// <param name="isLoadAssembly">是否从未加载程序集中获取类型。使用仅反射的方法检查目标类型,如果存在,则进行常规加载</param>
        /// <returns></returns>
        public static IEnumerable<Type> FindAllPlugins(Type baseType, Boolean isLoadAssembly) { return FindAllPlugins(baseType, isLoadAssembly, true); }

        /// <summary>查找所有非系统程序集中的所有插件</summary>
        /// <remarks>继承类所在的程序集会引用baseType所在的程序集,利用这一点可以做一定程度的性能优化。</remarks>
        /// <param name="baseType"></param>
        /// <param name="isLoadAssembly">是否从未加载程序集中获取类型。使用仅反射的方法检查目标类型,如果存在,则进行常规加载</param>
        /// <param name="excludeGlobalTypes">指示是否应检查来自所有引用程序集的类型。如果为 false,则检查来自所有引用程序集的类型。 否则,只检查来自非全局程序集缓存 (GAC) 引用的程序集的类型。</param>
        /// <returns></returns>
        internal static IEnumerable<Type> FindAllPlugins(Type baseType, Boolean isLoadAssembly, Boolean excludeGlobalTypes)
        {
            var baseAssemblyName = baseType.Assembly.GetName().Name;

            var list = new List<Type>();
            foreach (var item in GetAssemblies())
            {
                // 如果excludeGlobalTypes为true,则指检查来自非GAC引用的程序集
                if (excludeGlobalTypes && item.Asm.GlobalAssemblyCache) continue;

                // 不搜索系统程序集,不搜索未引用基类所在程序集的程序集,优化性能
                if (item.IsSystemAssembly || !IsReferencedFrom(item.Asm, baseAssemblyName)) continue;

                var ts = item.FindPlugins(baseType);
                if (ts != null && ts.Count > 0)
                {
                    foreach (var elm in ts)
                    {
                        if (!list.Contains(elm))
                        {
                            list.Add(elm);
                            yield return elm;
                        }
                    }
                }
            }
            if (isLoadAssembly)
            {
                foreach (var item in AssemblyX.ReflectionOnlyGetAssemblies())
                {
                    // 如果excludeGlobalTypes为true,则指检查来自非GAC引用的程序集
                    if (excludeGlobalTypes && item.Asm.GlobalAssemblyCache) continue;

                    // 不搜索系统程序集,不搜索未引用基类所在程序集的程序集,优化性能
                    if (item.IsSystemAssembly || !IsReferencedFrom(item.Asm, baseAssemblyName)) continue;

                    var ts = item.FindPlugins(baseType);
                    if (ts != null && ts.Count > 0)
                    {
                        // 真实加载
                        var asm2 = Assembly.LoadFile(item.Asm.Location);
                        ts = AssemblyX.Create(asm2).FindPlugins(baseType);

                        if (ts != null && ts.Count > 0)
                        {
                            foreach (var elm in ts)
                            {
                                if (!list.Contains(elm))
                                {
                                    list.Add(elm);
                                    yield return elm;
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary><paramref name="asm"/> 是否引用了 <paramref name="baseAsmName"/></summary>
        /// <param name="asm">程序集</param>
        /// <param name="baseAsmName">被引用程序集全名</param>
        /// <returns></returns>
        public static Boolean IsReferencedFrom(Assembly asm, String baseAsmName)
        {
            //if (asm.FullName.EqualIgnoreCase(baseAsmName)) return true;
            if (asm.GetName().Name.EqualIgnoreCase(baseAsmName)) return true;

            foreach (var item in asm.GetReferencedAssemblies())
            {
                //if (item.FullName.EqualIgnoreCase(baseAsmName)) return true;
                if (item.Name.EqualIgnoreCase(baseAsmName)) return true;
            }

            return false;
        }
        #endregion

        #region 静态加载
        /// <summary>获取指定程序域所有程序集</summary>
        /// <param name="domain"></param>
        /// <returns></returns>
        public static IEnumerable<AssemblyX> GetAssemblies(AppDomain domain)
        {
            if (domain == null) domain = AppDomain.CurrentDomain;

            var asms = domain.GetAssemblies();
            if (asms == null || asms.Length < 1) return Enumerable.Empty<AssemblyX>();

            //return asms.Select(item => Create(item));
            return from e in asms select Create(e);

            //foreach (var item in asms)
            //{
            //    yield return Create(item);
            //}
        }

        /// <summary>获取当前程序域所有程序集</summary>
        /// <returns></returns>
        public static IEnumerable<AssemblyX> GetAssemblies() { return GetAssemblies(AppDomain.CurrentDomain); }

        private static ICollection<String> _AssemblyPaths;
        /// <summary>程序集目录集合</summary>
        public static ICollection<String> AssemblyPaths { get { return _AssemblyPaths ?? (_AssemblyPaths = new HashSet<String>(StringComparer.OrdinalIgnoreCase)); } set { _AssemblyPaths = value; } }

        /// <summary>获取当前程序域所有只反射程序集的辅助类</summary>
        /// <returns></returns>
        public static IEnumerable<AssemblyX> ReflectionOnlyGetAssemblies()
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            if (HttpRuntime.AppDomainId != null) path = HttpRuntime.BinDirectory;

            // 先返回已加载的只加载程序集
            var loadeds2 = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().Select(e => Create(e)).ToList();
            foreach (var item in loadeds2)
            {
                yield return item;
            }

            foreach (var asm in ReflectionOnlyLoad(path)) yield return asm;

            foreach (var item in AssemblyPaths)
            {
                foreach (var asm in ReflectionOnlyLoad(item)) yield return asm;
            }
        }

        /// <summary>只反射加载指定路径的所有程序集</summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static IEnumerable<AssemblyX> ReflectionOnlyLoad(String path)
        {
            if (!Directory.Exists(path)) yield break;

            // 先返回已加载的只加载程序集
            var loadeds2 = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().Select(e => Create(e)).ToList();

            // 再去遍历目录
            var ss = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
            if (ss == null || ss.Length < 1) yield break;

            var loadeds = AssemblyX.GetAssemblies().ToList();

            foreach (var item in ss)
            {
                if (!item.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) &&
                    !item.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) continue;

                if (loadeds.Any(e => e.Location.EqualIgnoreCase(item)) || loadeds2.Any(e => e.Location.EqualIgnoreCase(item))) continue;

                AssemblyX asmx = null;
                try
                {
                    //Assembly asm = Assembly.ReflectionOnlyLoad(File.ReadAllBytes(item));
                    var asm = Assembly.ReflectionOnlyLoadFrom(item);

                    asmx = Create(asm);
                }
                catch { }

                if (asmx != null) yield return asmx;
            }
        }
        #endregion

        #region 重载
        /// <summary>已重载。</summary>
        /// <returns></returns>
        public override string ToString()
        {
            //return String.Format("{0} {1}", Name, Title);
            if (!String.IsNullOrEmpty(Title))
                return Title;
            else
                return Name;
        }

        /// <summary>判断两个程序集是否相同,避免引用加载和执行上下文加载的相同程序集显示不同</summary>
        /// <param name="asm1"></param>
        /// <param name="asm2"></param>
        /// <returns></returns>
        public static Boolean Equal(Assembly asm1, Assembly asm2)
        {
            if (asm1 == asm2) return true;

            return asm1.FullName == asm2.FullName;
        }
        #endregion
    }
}