NOP框架通過反射實現的類型查找器學習筆記


前言

最近對Nop框架裏面的引擎模塊比較感興趣,於是就研究了一下(nopCommerce_4.10_Source),發現裏面寫的東西相輔相成,不再贅述,這裏重點記一下對ITypeFinder 類型查找器學習遇到一些收穫進行記錄

什麼是反射?

		反射是使用另外一種方法來調用獲取應用程序或者程序組件的一些信息,這個應用程序可以是我們正在運行的也可以是還沒有運行的,
只要是能夠被.NET調用的文件都可以使用反射來獲取文件的信息,
如我們衆所周知的.dll、.exe、com組件等都可以使用反射來獲取文件的信息,
同時也可以使用反射來調用這些組件或者程序。
																							上面這段是複製人家的 
																							作者:zhang_xinxiu 
																							來源:CSDN 
																							原文:https://blog.csdn.net/zhang_xinxiu/article/details/19502575 
																							版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!  

什麼是類型查找器?

類型查找器,顧名思義,就是查找對應類型的代碼實現;
在Nop中所實現的類型查找器,主要是運用在 IOC中,
通過向類型查找器查找在當前域下的接口實現類,並通過IOC
將它們注入到容器中,實現控制反轉

代碼分析

梳理整體邏輯及大致思路


看別人的源碼,首先要了解作者在寫程序時候的設計思路,第一步是是從整體一個宏觀全局去了解,然後往下再各個模塊及去分析,在此,我就大膽的對類型查找器這一小塊的代碼進行一個思路梳理及分析:
首先是所寫的幾個方法函數,其中四個方法都是通過類型去查找相應的實現類,還有一個是獲取需要查找的程序集,

  		/// <summary>
        /// 根據類型查找對應的類
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isConcreteClass"></param>
        /// <returns></returns>
        IEnumerable<Type> ClassFindOfType<T>(bool isConcreteClass=true);

        /// <summary>
        /// 根據類型查找對應的類
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isConcreteClass"></param>
        /// <returns></returns>
        IEnumerable<Type> ClassFindOfType(Type typeForm, bool isConcreteClass = true);

        /// <summary>
        /// 根據類型查找對應的類
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isConcreteClass"></param>
        /// <returns></returns>
        IEnumerable<Type> ClassFindOfType<T>(IList<Assembly> assemblies, bool isConcreteClass = true);

        /// <summary>
        /// 根據類型查找對應的類
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isConcreteClass"></param>
        /// <returns></returns>
        IEnumerable<Type> ClassFindOfType(Type typeForm, IList<Assembly> assemblies, bool isConcreteClass = true);

        /// <summary>
        /// 獲取程序集
        /// </summary>
        /// <returns></returns>
        IList<Assembly> LoadAssemblies();

首先說獲取程序集:

		/// <summary>
        /// 獲取程序集
        /// </summary>
        /// <returns></returns>
        public IList<Assembly> LoadAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
            if (IsLoadAppDomainAssembly)
            {
                AddAssemblyInAppDomain(assemblies);
            }
            AddAssemblyInConfig(assemblies);
            return assemblies;  
        }

在獲取程序集的是是否對是否獲取當前域下所有的程序集這一條件進行了判斷
默認的情況下是true的;
然後如果獲取所有程序集的話就會執行AddAssemblyInAppDomain(我自己重新寫的代碼,方法名和源碼不一樣,原諒我的渣渣英語) 這個私有方法

 /// <summary>
        /// 獲取當前域的程序集
        /// </summary>
        /// <param name="assemblies"></param>
        private void AddAssemblyInAppDomain(List<Assembly> assemblies)
        {
            Assembly[] assemblyArrary = App.GetAssemblies();
            foreach (var assembly in assemblyArrary)
            {
                if (CheckProperty(assembly.FullName))
                {
                    if (!assemblies.Contains(assembly))
                    {
                        assemblies.Add(assembly);
                    }
                }
            }
        }

這個方法主要就是獲取當前域下面所有程序及的。而CheckProperty()這個方法 主要是和需要跳過的一些程序集進行篩選,主要代碼如下:
首先聲明一個字段,裏面記錄需要跳過的程序集名稱組成的正則,還有一個字段是記錄需要的程序集,一般默認貪婪匹配所有的程序集

        /// <summary>
        /// 跳過的程序集名稱
        /// </summary>
 		public string SkipAssembliesName { get; set; } = "^ System |^ mscorlib |^ Microsoft |^ AjaxControlToolkit |^ Antlr3 |^ Autofac |^ AutoMapper |^ Castle |^ ComponentArt |^ CppCodeProvider |^ DotNetOpenAuth |^ EntityFramework |^ EPPlus |^ FluentValidation |^ ImageResizer |^ itextsharp |^ log4net |^ MaxMind |^ MbUnit |^ MiniProfiler |^ Mono.Math |^ MvcContrib |^ Newtonsoft |^ NHibernate |^ nunit |^ Org.Mentalis |^ PerlRegex |^ QuickGraph |^ Recaptcha |^ Remotion |^ RestSharp |^ Rhino |^ Telerik |^ Iesi |^ TestDriven |^ TestFu |^ UserAgentStringLibrary |^ VJSharpCodeProvider |^ WebActivator |^ WebDev |^ WebGrease |^ Quartz |^ Owin |^ Microsoft.Owin";
 		/// <summary>
        /// 需要查詢的程序集名稱
        /// </summary>
        public string LoadAssembliesName { get; set; } = ".*";

然後看註釋

      /// <summary>
        /// 對需要跳過的和需要獲取的程序集進行對比
        /// </summary>
        /// <param name="FullName"></param>
        /// <returns></returns>
        private bool CheckProperty(string FullName)
        {
            return !CheckProperty(FullName, SkipAssembliesName) && CheckProperty(FullName, LoadAssembliesName);
        }

        /// <summary>
        /// 對需要跳過的和需要獲取的程序集進行對比
        /// </summary>
        /// <param name="FullName"></param>
        /// <param name="LoadAssembliesName"></param>
        /// <returns></returns>
        private bool CheckProperty(string FullName, string LoadAssembliesName)
        {
          return Regex.IsMatch(FullName, LoadAssembliesName, RegexOptions.IgnoreCase|RegexOptions.Compiled);
        }

當所有程序集都查找完畢以後就是這個方法的主要用途了,該方法首先主要就是用於,通過遍歷獲取到的程序集來對程序集所繼承的類型逐個分析:

		/// <summary>
        /// 根據類型查詢類
        /// </summary>
        /// <param name="typeForm"></param>
        /// <param name="assemblies"></param>
        /// <param name="isConcreteClass"></param>
        /// <returns></returns>
        public IEnumerable<Type> ClassFindOfType(Type typeForm, IList<Assembly> assemblies, bool isConcreteClass = true)
        {
            //首先實例化一個返回值
            List<Type> typeResult = new List<Type>();
            try
            {
                foreach (var assembly in assemblies)
                {
                    Type[] typeArrary = null;
                    try
                    {
                        typeArrary = assembly.GetTypes();
                    }
                    catch (Exception)
                    {
                        if (!IsIgnoreError)
                        {
                            throw;
                        }
                    }
                    if (typeArrary == null)
                    {
                        continue;
                    }
                    foreach (var type in typeArrary)
                    {
                        if (typeForm.IsAssignableFrom(type) || type.IsGenericTypeDefinition && DoesTypeImplementOpenGeneric(type, typeForm))
                        {
                            if (isConcreteClass)
                            {
                                if (!type.IsAbstract&&!type.IsInterface)
                                {
                                    typeResult.Add(type);
                                }
                            }
                            else
                            {
                                typeResult.Add(type);
                            }
                        }
                    }
                }
                return typeResult;
            }
            catch (Exception)
            {

                throw;
            }
        }

首先將 assignTypeFrom.IsAssignableFrom(t)作爲條件進行判斷,
這個方法所判斷的就是 當前傳入的類型是否與查找到的程序集的類型,同出一脈。
當這個方法判斷過後
就會 判斷 (assignTypeFrom.IsGenericTypeDefinition || DoesTypeImplementOpenGeneric(t, assignTypeFrom)) 這個條件,這個條件所實現的含義就是: 當前傳入的類型是否可以構造其他泛型類型,而後通過私有方法:

               private bool DoesTypeImplementOpenGeneric(Type type,Type typeForm)
        {
            //構造當前類型的泛型類型的Type對象。
            Type typeDefinition = type.GetGenericTypeDefinition();
            foreach (var interFaces in type.FindInterfaces((filter,objects)=>true,null))
            {
                if (interFaces.IsGenericType)
                {
                    bool IsMatch = typeForm.IsAssignableFrom(interFaces);
                    return IsMatch;
                }
            }
            return false;
        }

從上面的方法可以看出,其實最後得到的就是當前查找到的類型所有所繼承的類型是否與當前所傳入的類型的泛型類型是否同出一脈。
當以上兩個條件均爲True的時候(源碼是將他們全都是False情況下進行判斷,然後跳出循環,我個人習慣是全都寫成True進行下一步),這個時候開始判斷我們需要的是否只是具體的實現類,如果只需要具體類,在進行是否是接口或者抽象類的判斷然後添加到最初實例化的返回集合中;

結語

對於Nop框架本人也是剛開始進行深入的研究,奈何本人開發資歷淺顯,很多東西都不能明白,不能和當世的個爲大神對比,只能一個人一步一個腳印往前走,希望如果哪位大神撥冗翻閱拙作希望給小子指出文章的不足,小子萬分感激

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章