類型查找器學習筆記


前言

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

什麼是類型查找器?

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

代碼分析

	 /// <summary>	
	 /// 類型查找器
	/// 通過類型查找器,可以查找當前運行域中的類
	/// </summary>
	public interface ITypeFinder
	{
		/// <summary>
		/// 獲取程序集
		/// </summary>
	 	/// <returns></returns>
		IList<Assembly> GetAssemblies();

        /// <summary>
        /// 查找類型
        /// </summary>
        /// <typeparam name="T">類型</typeparam>
        /// <param name="onlyConcreteClasses">是否是具體類</param>
        /// <returns></returns>
        IEnumerable<Type> FindClassOfType<T>(bool onlyConcreteClasses = true);

        /// <summary>
        /// 查找類型
        /// </summary>
        /// <param name="type">類型</param>
        /// <param name="onlyConcreteClasses">是否是具體類</param>
        /// <returns></returns>
        IEnumerable<Type> FindClassOfType(Type type,bool onlyConcreteClasses=true);

        /// <summary>
        /// 查找類型
        /// </summary>
        /// <param name="assemblies">程序集</param>
        /// <param name="onlyConcreteClasses">是否是具體類</param>
        /// <returns></returns>
        IEnumerable<Type> FindClassOfType<T>(IList<Assembly> assemblies, bool onlyConcreteClasses = true);

        /// <summary>
        /// 查找類型
        /// </summary>
        /// <param name="type">類型</param>
        /// <param name="assemblies">程序集</param>
        /// <param name="onlyConcreteClasses">是否是具體類</param>
        /// <returns></returns>
        IEnumerable<Type> FindClassOfType(Type type, IList<Assembly> assemblies, bool onlyConcreteClasses = true);

以上是類查找器的接口文件,主要通過四個方法實現對不同場景需要來查找類

查找當前域所運行的程序集類型

public class AppDomainTypeFinder : ITypeFinder
    {
        #region 變量 

        //是否加載當前程序域
        private bool loadAppDomainAssemblies = true;
        //是否忽略反射的錯誤
        private bool isIgnoreReflectionErrors = true;
        //設置需要加載的程序集
        private List<string> assembliesName = new List<string>();
        //跳過不必查找的程序集
        private string assemblySkipLoadingPattern = "^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";
        //需要查找的程序集
        private string assemblyRestrictToLoadingPattern = ".*";

        #endregion


        #region 屬性

        //是否加載當前程序域
        public bool LoadAppDomainAssemblies
        {
            get => loadAppDomainAssemblies;
            set => loadAppDomainAssemblies = value;
        }

        //是否忽略反射的錯誤
        public bool IsIgnoreReflectionErrors
        {
            get => isIgnoreReflectionErrors;
            set => isIgnoreReflectionErrors = value;
        }

        /// <summary>
        /// 需要加載的程序集名稱
        /// </summary>
        public List<string> AssemblyName
        {
            get=> assembliesName;
            set => assembliesName=value;
        }

        /// <summary>
        /// 需要跳過的程序集
        /// </summary>
        public string AssemblySkipLoadingPattern
        {
            get => assemblySkipLoadingPattern;
            set => assemblySkipLoadingPattern += value;
        }

        public string AssemblyRestrictToLoadingPattern
        {
            get => assemblyRestrictToLoadingPattern;
            set => assemblyRestrictToLoadingPattern = value;
        }

        #endregion

        #region Method

        public IEnumerable<Type> FindClassOfType<T>(bool onlyConcreteClasses=true)
        {
            return FindClassOfType(typeof(T), onlyConcreteClasses);
        }

        public IEnumerable<Type> FindClassOfType(Type type, bool onlyConcreteClasses = true)
        {

            return FindClassOfType(type,GetAssemblies(), onlyConcreteClasses);
        }

        public IEnumerable<Type> FindClassOfType<T>(IList<Assembly> assemblies, bool onlyConcreteClasses = true)
        {

            return FindClassOfType(typeof(T), GetAssemblies(), onlyConcreteClasses);
        }


        public IEnumerable<Type> FindClassOfType(Type typeForm, IList<Assembly> assemblies, bool onlyConcreteClasses = true)
        {
            try
            {
                List<Type> resultTypes = new List<Type>();
                foreach (var assembly in assemblies)
                {
                    Type[] types = null;
                    try
                    {
                        types=assembly.GetTypes();//獲取當前程序集中所有的類型
                    }
                    catch (Exception)
                    {
                        //EF6不支持反射類型
                        if (!isIgnoreReflectionErrors)
                        {
                            throw;
                        }
                    }
                    if (types != null)//type查找到類型
                    {
                        foreach (var type in types)
                        {     //(1)、typeForm和當前類型是同一類型,或者typeForm在type的繼承結構中(一個家譜)
                              //或者當前類型是type的實現接口
                              //或者type是泛型接口,當前類型剛好是type的約束
                              //或者typeForm是值類型,當前類型是可空的類型
                              //均返回True
                              //(2)、 如果typeForm 對象表示泛型類型定義,則爲 true;否則爲 false


                            if (typeForm.IsAssignableFrom(type) || (typeForm.IsGenericParameter && DoesTypeImplementOpenGeneric(type, typeForm)))
                            {
                                if (!type.IsInterface)
                                {
                                    if (onlyConcreteClasses)//判斷是否是查詢需要具體類
                                    {
                                        if (type.IsClass || !type.IsAbstract)
                                        {
                                            resultTypes.Add(type);
                                        }
                                    }
                                    else
                                    {
                                        resultTypes.Add(type);
                                    }
                                }
                            }

                        }
                    }
                }
                return resultTypes;
            }
            catch (Exception)
            {

                throw;
            }
        }

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

        #endregion

        #region Privat Method

        /// <summary>
        /// 獲取當前應用域下所有運行的程序集
        /// </summary>
        /// <param name="assemblies"></param>
        private void AddAssemblyInAppDomain(List<Assembly> assemblies)
        {
            //獲取當前程序域下的所有程序集
           Assembly[] types= AppDomain.CurrentDomain.GetAssemblies();
            foreach (var type in types)
            {
                if (Check(type.FullName))
                {
                    assemblies.Add(type);
                }
            }
        }

        /// <summary>
        /// 檢查是否符合要查找的程序集
        /// </summary>
        /// <param name="fullName"></param>
        /// <returns></returns>
        private bool Check(string fullName)
        {
            return !Check(fullName, assemblySkipLoadingPattern) && Check(fullName, assemblyRestrictToLoadingPattern);
        }

        /// <summary>
        /// 檢查是否符合要查找的程序集
        /// </summary>
        /// <param name="fullName"></param>
        /// <param name="loadingPattern"></param>
        /// <returns></returns>
        private bool Check(string fullName, string loadingPattern)
        {
           return Regex.IsMatch(fullName, loadingPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        /// <summary>
        /// 獲取配置需要獲取的程序集
        /// </summary>
        /// <param name="assemblies"></param>
        private void AddAssemblyInConfig(List<Assembly> assemblies)
        {

            AssemblyName?.ForEach(item=>
            {
                Assembly assembly = Assembly.Load(item);
                if (!assemblies.Contains(assembly))
                {
                    assemblies.Add(assembly);
                }
            });
        }

        /// <summary>
        /// 當前類型是否實現泛型
        /// </summary>
        /// <returns></returns>
        private bool DoesTypeImplementOpenGeneric(Type type, Type generic )
        {
            var genericTypeDefinition = generic.GetGenericTypeDefinition();//表示通用類型的類型對象,可從中構造當前類型。
            foreach (var item in type.FindInterfaces((typeFilter, objects) => true, null))
            {
                if (!item.IsGenericType)//判斷是否是泛型
                {
                    continue;
                }
                return genericTypeDefinition.IsAssignableFrom(item.GetGenericTypeDefinition());
            }    
            return true;
        }
        #endregion
    }

遇到的問題

上面的代碼是我在自己看完框架源碼以後,自己重新建了個項目又敲了一遍,可能我能力不是很夠,期間還刪了部分代碼,因爲實在研究不出這段代碼是幹嘛的;
比如:
問題一:
//框架源碼


        /// <summary>Gets the assemblies related to the current implementation.</summary>
        /// <returns>A list of assemblies that should be loaded by the Nop factory.</returns>
        public virtual IList<Assembly> GetAssemblies()
        {
            var addedAssemblyNames = new List<string>();
            var assemblies = new List<Assembly>();

            if (LoadAppDomainAssemblies)
                AddAssembliesInAppDomain(addedAssemblyNames, assemblies);
            AddConfiguredAssemblies(addedAssemblyNames, assemblies);

            return assemblies;
        }

        #endregion

這個方法裏面實例化了一個
var addedAssemblyNames = new List();
但是我看了半天,發現這個addedAssemblyName實例化出來以後最後並沒有返回回去,所有看的我百思不得其解。

//框架源碼end

問題二:

foreach (var item in type.FindInterfaces((typeFilter, objects) => true, null))
            {
                if (!item.IsGenericType)//判斷是否是泛型
                {
                    continue;
                }
                return genericTypeDefinition.IsAssignableFrom(item.GetGenericTypeDefinition());
            }   

對於上面一段代碼中的
Type.FindInterFaces()
方法剛開始並不知道是個什麼意思。
於是就去MSDN上面看微軟的文檔,
然後看着微軟的示例代碼進行各式各樣的編寫測試,
得到的結果是:
FindInterfaces 是查找當前Type所繼承的接口,然後與括號內的參數進行邏輯處理,而這個方法所需要的參數 第一個是個Acount委託,一般是在裏面編寫對比的邏輯,返回的類型是布爾類型,而該邏輯處理的就是後面的參數與當前Type所繼承的接口,如果返回true就返回所繼承的對應的接口類型,如果像上面代碼這樣不給參數賦值的話,就是返回當前Type繼承的所有接口

結語

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

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