程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 四、面向雲的.net core開發框架基礎設施層-應用程序集和類的查找,.netcore

四、面向雲的.net core開發框架基礎設施層-應用程序集和類的查找,.netcore

編輯:關於.NET

四、面向雲的.net core開發框架基礎設施層-應用程序集和類的查找,.netcore


在編寫開發框架的時候,經常會遇到要找出應用所用到的所有程序集和類,然後進行下一步的處理。

例如,我們有一個通用控件類BaseControl,各種富文本編輯器控件、表格控件、分頁控件等都繼承於通用控件類BaseControl。甚至CMS這個項目的評論等控件也會繼承該通用控件類BaseControl。我們有一個需求,就是要做一個下拉列表,列出所有的控件。因為控件會分散在不同的程序集中,這樣我們必然會搜索當前應用中的所有程序集,從中找出所有繼承於BaseControl的控件子類。這就是控件的列表。(如果我懶病不發作,能夠寫的夠久的話,自定義表單、自定義查詢等技術點可以看到這個需求。)

下面的方法是找到所有的應用程序集:

 1         private static IEnumerable<Assembly> GetAssemblies()
 2         {
 3             List<Assembly> assemblies = new List<Assembly>();
 4 
 5             //以下2行,總是認為所有的個人程序集都依賴於core
 6             Type type = typeof(ReflectionHelper);
 7 
 8             var libs = DependencyContext.Default.CompileLibraries;
 9             foreach (CompilationLibrary lib in libs)
10             {
11                 //if (lib.Name.StartsWith("Microsoft") || lib.Name.StartsWith("System") || lib.Name.Contains(".System.") || lib.Name.StartsWith("NuGet") || lib.Name.StartsWith("AutoMapper")) continue;
12                 if (lib.Serviceable) continue;
13                 if (lib.Type == "package") continue;
14 
15                 var assembly = Assembly.Load(new AssemblyName(lib.Name));
16                 assemblies.Add(assembly);
17 
18                 //以下,總是認為所有的個人程序集都依賴於core
19 
20                 ////過濾掉“動態生成的”
21                 //if (assembly.IsDynamic) continue;
22 
23                 //if (assembly.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", ""))
24                 //{
25                 //    assemblies.Add(assembly);
26                 //    continue;
27                 //}
28 
29                 //if (assembly.GetReferencedAssemblies().Any(ass => ass.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", "")))
30                 //{
31                 //    assemblies.Add(assembly);
32                 //}
33             }
34 
35             return assemblies;
36         }

此處有個假設,第6行Type type = typeof(ReflectionHelper)。其中ReflectionHelper是核心應用程序集中的一個靜態類,而核心應用程序集假設會被所有的應用程序集所引用。如果該假設不成立,需要將19-22行的注釋去掉,針對每個找到的程序集獲取所有引用的程序集。

if (lib.Serviceable) continue;和if (lib.Type == "package") continue; 這兩行的意思是排除所有的系統程序集、Nuget下載包,減少搜索范圍,提高效率。(這2行暫未最終確認。)

找到所有應用程序集後,下一步該獲取所有繼承於BaseControl的控件子類。因為控件子類繼承於BaseControl,因此子類所在的應用程序集必然引用BaseControl的應用程序集。通用寫法如下:

 1         #region 類型搜索
 2         /// <summary>
 3         /// 獲取子類型
 4         /// </summary>
 5         /// <param name="type">父類型</param>
 6         /// <returns></returns>
 7         public static IEnumerable<Type> GetSubTypes(Type type)
 8         {
 9             var assemblies = _Assemblies.Where(a =>
10             {
11                 Assembly assembly = type.GetTypeInfo().Assembly;
12                 //基類所在程序集或依賴於基類的其他程序集
13                 return a.FullName == assembly.FullName || a.GetReferencedAssemblies().Any(ra => ra.FullName == assembly.FullName);
14             });
15 
16             TypeInfo typeInfo = type.GetTypeInfo();
17 
18             return assemblies.SelectMany(a =>
19             {
20                 return a.GetTypes().Where(t =>
21                 {
22                     if (type == t)
23                     {
24                         return false;
25                     }
26 
27                     TypeInfo tInfo = t.GetTypeInfo();
28 
29                     if (tInfo.IsAbstract || !tInfo.IsClass || !tInfo.IsPublic)
30                     {
31                         return false;
32                     }
33 
34                     if (typeInfo.IsGenericTypeDefinition)
35                     {
36                         return type.IsAssignableFromGenericType(t);
37                     }
38 
39                     return type.IsAssignableFrom(t);
40                 });
41             });
42         }
43 
44         /// <summary>
45         /// 獲取子類型
46         /// </summary>
47         /// <typeparam name="T">父類型</typeparam>
48         /// <returns></returns>
49         public static IEnumerable<Type> GetSubTypes<T>()
50         {
51             return GetSubTypes(typeof(T));
52         }
53         #endregion

其中_Assemblies是從GetAssemblies()方法返回的結果。

這樣就能夠獲取當前的子類列表IEnumerable<Type>,可是如果用下拉列表展示,總不能顯示類似namespace.classname, assemblyname的樣子吧,這樣會被客戶罵的。應該下拉出來的是中文名,例如富文本編輯器、文件上傳、分頁、自動完成等。

如果我們在BaseControl中增加一個抽象的Name屬性,各個子類實現時override這個屬性,標識該控件的中文名,倒是可以實現,不過在獲取Name屬性時,必須要實例化各個子類,天知道子類的構造函數有哪些參數。因此我們應該采取其他方式。建一個TypeNameAttribute。具體實現如下:

  1     /// <summary>
  2     /// 子類中,甚至TypeName,包括中英文及屬性,以便反射使用
  3     /// </summary>
  4     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
  5     public class TypeNameAttribute : Attribute
  6     {
  7         private string _Code, _Name, _Description;
  8         /// <summary>
  9         /// 英文
 10         /// </summary>
 11         public string Code
 12         {
 13             get
 14             {
 15                 return _Code;
 16             }
 17             set
 18             {
 19                 _Code = value;
 20             }
 21         }
 22         /// <summary>
 23         /// 中文
 24         /// </summary>
 25         public string Name
 26         {
 27             get
 28             {
 29                 return _Name;
 30             }
 31             set
 32             {
 33                 _Name = value;
 34             }
 35         }
 36         /// <summary>
 37         /// 描述
 38         /// </summary>
 39         public string Description
 40         {
 41             get
 42             {
 43                 return _Description;
 44             }
 45             set
 46             {
 47                 _Description = value;
 48             }
 49         }
 50         /// <summary>
 51         /// 構造函數
 52         /// </summary>
 53         /// <param name="code">英文</param>
 54         /// <param name="name">中文</param>
 55         /// <param name="description">描述</param>
 56         public TypeNameAttribute(string code, string name, string description)
 57         {
 58             this._Code = code;
 59             this._Name = name;
 60             this._Description = description;
 61         }
 62 
 63         /// <summary>
 64         /// 構造函數
 65         /// </summary>
 66         /// <param name="code">英文</param>
 67         /// <param name="name">中文</param>
 68         public TypeNameAttribute(string code, string name) : this(code, name, string.Empty)
 69         {
 70         }
 71     }
 72 
 73     /// <summary>
 74     /// TypeName的工具類
 75     /// </summary>
 76     public static class TypeNameHelper
 77     {
 78         public static ConcurrentDictionary<Type, List<TypeNameHelperInfo>> list = new ConcurrentDictionary<Type, List<TypeNameHelperInfo>>();
 79 
 80         public static TypeNameHelperInfo GetTypeNameHelperInfo<T>(string code)
 81         {
 82             List<TypeNameHelperInfo> list = GetTypeNameHelperList<T>();
 83 
 84             return list.SingleOrDefault(info => info.Code == code);
 85         }
 86 
 87         /// <summary>
 88         /// 根據基類,獲取所有子類的TypeName
 89         /// </summary>
 90         /// <typeparam name="T">基類型</typeparam>
 91         /// <returns>子類的TypeName信息</returns>
 92         public static List<TypeNameHelperInfo> GetTypeNameHelperList<T>()
 93         {
 94             if (list.ContainsKey(typeof(T)))
 95             {
 96                 return list[typeof(T)];
 97             }
 98 
 99             List<TypeNameHelperInfo> result = new List<TypeNameHelperInfo>();
100 
101             IEnumerable<Type> typeList = ReflectionHelper.GetSubTypes<T>();
102 
103             foreach (Type type in typeList)
104             {
105                 try
106                 {
107                     TypeNameAttribute attribute = ReflectionHelper.GetCustomAttribute<TypeNameAttribute>(type);
108                     result.Add(new TypeNameHelperInfo()
109                     {
110                         Code = attribute.Code,
111                         Name = attribute.Name,
112                         Description = attribute.Description,
113                         Type = type
114                     });
115                 }
116                 catch
117                 {
118                 }
119             }
120 
121             list[typeof(T)] = result;
122 
123             return result;
124         }
125     }
126 
127     /// <summary>
128     /// TypeName的信息類
129     /// </summary>
130     public class TypeNameHelperInfo
131     {
132         /// <summary>
133         /// 英文
134         /// </summary>
135         public string Code { get; set; }
136         /// <summary>
137         /// 中文
138         /// </summary>
139         public string Name { get; set; }
140         /// <summary>
141         /// 描述
142         /// </summary>
143         public string Description { get; set; }
144         /// <summary>
145         /// 類型
146         /// </summary>
147         public Type Type { get; set; }
148     }

最終就可以通過TypeNameHelper.GetTypeNameHelperList<BaseControl>()就可以獲取所有的控件子類,子類列表存放在List<TypeNameHelperInfo>。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved