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