ClassHelper.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. namespace Masuit.Tools.Reflection
  7. {
  8. /// <summary>
  9. /// 类帮助器,可以动态对类,类成员进行控制(添加,删除),目前只支持属性控制。
  10. /// 注意,属性以外的其它成员会被清空,功能还有待完善,使其不影响其它成员。
  11. /// </summary>
  12. public static class ClassHelper
  13. {
  14. #region 公有方法
  15. /// <summary>
  16. /// 根据类的类型型创建类实例。
  17. /// </summary>
  18. /// <param name="t">将要创建的类型。</param>
  19. /// <returns>返回创建的类实例。</returns>
  20. public static object CreateInstance(this Type t)
  21. {
  22. return Activator.CreateInstance(t);
  23. }
  24. /// <summary>
  25. /// 根据类的名称,属性列表创建型实例。
  26. /// </summary>
  27. /// <param name="className">将要创建的类的名称。</param>
  28. /// <param name="lcpi">将要创建的类的属性列表。</param>
  29. /// <returns>返回创建的类实例</returns>
  30. public static object CreateInstance(string className, List<CustPropertyInfo> lcpi)
  31. {
  32. return Activator.CreateInstance(AddProperty(BuildType(className), lcpi));
  33. }
  34. /// <summary>
  35. /// 根据属性列表创建类的实例,默认类名为DefaultClass,由于生成的类不是强类型,所以类名可以忽略。
  36. /// </summary>
  37. /// <param name="lcpi">将要创建的类的属性列表</param>
  38. /// <returns>返回创建的类的实例。</returns>
  39. public static object CreateInstance(List<CustPropertyInfo> lcpi)
  40. {
  41. return CreateInstance("DefaultClass", lcpi);
  42. }
  43. /// <summary>
  44. /// 创建一个没有成员的类型的实例,类名为"DefaultClass"。
  45. /// </summary>
  46. /// <returns>返回创建的类型的实例。</returns>
  47. public static Type BuildType()
  48. {
  49. return BuildType("DefaultClass");
  50. }
  51. /// <summary>
  52. /// 根据类名创建一个没有成员的类型的实例。
  53. /// </summary>
  54. /// <param name="className">将要创建的类型的实例的类名。</param>
  55. /// <returns>返回创建的类型的实例。</returns>
  56. public static Type BuildType(string className)
  57. {
  58. AssemblyName myAsmName = new AssemblyName
  59. {
  60. Name = "MyDynamicAssembly"
  61. };
  62. //创建一个程序集,设置为AssemblyBuilderAccess.RunAndCollect。
  63. AssemblyBuilder myAsmBuilder = AssemblyBuilder.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndCollect);
  64. //创建一个单模程序块。
  65. ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name);
  66. //创建TypeBuilder。
  67. TypeBuilder myTypeBuilder = myModBuilder.DefineType(className, TypeAttributes.Public);
  68. //创建类型。
  69. Type retval = myTypeBuilder.CreateType();
  70. //保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。
  71. //myAsmBuilder.Save(myAsmName.Name + ".dll");
  72. return retval;
  73. }
  74. /// <summary>
  75. /// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。
  76. /// </summary>
  77. /// <param name="classType">指定类型的实例。</param>
  78. /// <param name="lcpi">表示属性的一个列表。</param>
  79. /// <returns>返回处理过的类型的实例。</returns>
  80. public static Type AddProperty(this Type classType, List<CustPropertyInfo> lcpi)
  81. {
  82. //合并先前的属性,以便一起在下一步进行处理。
  83. MergeProperty(classType, lcpi);
  84. //把属性加入到Type。
  85. return AddPropertyToType(classType, lcpi);
  86. }
  87. /// <summary>
  88. /// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。
  89. /// </summary>
  90. /// <param name="classType">指定类型的实例。</param>
  91. /// <param name="cpi">表示一个属性。</param>
  92. /// <returns>返回处理过的类型的实例。</returns>
  93. public static Type AddProperty(this Type classType, CustPropertyInfo cpi)
  94. {
  95. List<CustPropertyInfo> lcpi = new List<CustPropertyInfo>
  96. {
  97. cpi
  98. };
  99. //合并先前的属性,以便一起在下一步进行处理。
  100. MergeProperty(classType, lcpi);
  101. //把属性加入到Type。
  102. return AddPropertyToType(classType, lcpi);
  103. }
  104. /// <summary>
  105. /// 给对象实例添加新属性并返回新对象实例
  106. /// </summary>
  107. /// <param name="obj"></param>
  108. /// <param name="lcpi">自定义属性对象集合</param>
  109. /// <returns></returns>
  110. public static object AddProperty(this object obj, List<CustPropertyInfo> lcpi)
  111. {
  112. Type originType = obj.GetType();
  113. var customs = lcpi.ToDictionary(i => i.PropertyName, i => i.PropertyValue);
  114. var dest = AddProperty(originType, lcpi).CreateInstance();
  115. foreach (var originProperty in originType.GetProperties())
  116. {
  117. dest.SetProperty(originProperty.Name, originProperty.GetValue(obj));
  118. }
  119. foreach (var cpi in customs)
  120. {
  121. dest.SetProperty(cpi.Key, cpi.Value);
  122. }
  123. return dest;
  124. }
  125. /// <summary>
  126. /// 给对象实例添加新属性并返回新对象实例
  127. /// </summary>
  128. /// <param name="obj"></param>
  129. /// <param name="cpi">自定义属性对象</param>
  130. /// <returns></returns>
  131. public static object AddProperty(this object obj, CustPropertyInfo cpi)
  132. {
  133. return AddProperty(obj, new List<CustPropertyInfo>() { cpi });
  134. }
  135. /// <summary>
  136. /// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。
  137. /// </summary>
  138. /// <param name="classType">指定类型的实例。</param>
  139. /// <param name="propertyName">要移除的属性。</param>
  140. /// <returns>返回处理过的类型的实例。</returns>
  141. public static Type DeleteProperty(this Type classType, string propertyName)
  142. {
  143. List<string> ls = new List<string>
  144. {
  145. propertyName
  146. };
  147. //合并先前的属性,以便一起在下一步进行处理。
  148. List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls);
  149. //把属性加入到Type。
  150. return AddPropertyToType(classType, lcpi);
  151. }
  152. /// <summary>
  153. /// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。
  154. /// </summary>
  155. /// <param name="classType">指定类型的实例。</param>
  156. /// <param name="propertyNames">要移除的属性列表。</param>
  157. /// <returns>返回处理过的类型的实例。</returns>
  158. public static Type DeleteProperty(this Type classType, List<string> propertyNames)
  159. {
  160. //合并先前的属性,以便一起在下一步进行处理。
  161. List<CustPropertyInfo> lcpi = SeparateProperty(classType, propertyNames);
  162. //把属性加入到Type。
  163. return AddPropertyToType(classType, lcpi);
  164. }
  165. /// <summary>
  166. /// 删除对象的属性并返回新对象实例
  167. /// </summary>
  168. /// <param name="obj"></param>
  169. /// <param name="propertyNames">属性名集合</param>
  170. /// <returns></returns>
  171. public static object DeleteProperty(this object obj, List<string> propertyNames)
  172. {
  173. PropertyInfo[] oldProperties = obj.GetType().GetProperties();
  174. Type t = obj.GetType();
  175. foreach (string p in propertyNames)
  176. {
  177. t = t.DeleteProperty(p);
  178. }
  179. var newInstance = t.CreateInstance();
  180. foreach (var p in newInstance.GetProperties())
  181. {
  182. newInstance.SetProperty(p.Name, oldProperties.FirstOrDefault(i => i.Name.Equals(p.Name)).GetValue(obj));
  183. }
  184. return newInstance;
  185. }
  186. /// <summary>
  187. /// 删除对象的属性并返回新对象实例
  188. /// </summary>
  189. /// <param name="obj"></param>
  190. /// <param name="property">属性名</param>
  191. /// <returns></returns>
  192. public static object DeleteProperty(this object obj, string property)
  193. {
  194. return DeleteProperty(obj, new List<string>() { property });
  195. }
  196. #endregion
  197. #region 私有方法
  198. /// <summary>
  199. /// 把类型的实例t和lcpi参数里的属性进行合并。
  200. /// </summary>
  201. /// <param name="t">实例t</param>
  202. /// <param name="lcpi">里面包含属性列表的信息。</param>
  203. private static void MergeProperty(Type t, List<CustPropertyInfo> lcpi)
  204. {
  205. foreach (PropertyInfo pi in t.GetProperties())
  206. {
  207. CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType, pi.Name);
  208. lcpi.Add(cpi);
  209. }
  210. }
  211. /// <summary>
  212. /// 从类型的实例t的属性移除属性列表lcpi,返回的新属性列表在lcpi中。
  213. /// </summary>
  214. /// <param name="t">类型的实例t。</param>
  215. /// <param name="ls">要移除的属性列表。</param>
  216. private static List<CustPropertyInfo> SeparateProperty(Type t, List<string> ls)
  217. {
  218. List<CustPropertyInfo> ret = new List<CustPropertyInfo>();
  219. foreach (PropertyInfo pi in t.GetProperties())
  220. {
  221. foreach (string s in ls)
  222. {
  223. if (pi.Name != s)
  224. {
  225. CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType, pi.Name);
  226. ret.Add(cpi);
  227. }
  228. }
  229. }
  230. return ret;
  231. }
  232. /// <summary>
  233. /// 把lcpi参数里的属性加入到myTypeBuilder中。注意:该操作会将其它成员清除掉,其功能有待完善。
  234. /// </summary>
  235. /// <param name="myTypeBuilder">类型构造器的实例。</param>
  236. /// <param name="lcpi">里面包含属性列表的信息。</param>
  237. private static void AddPropertyToTypeBuilder(TypeBuilder myTypeBuilder, List<CustPropertyInfo> lcpi)
  238. {
  239. // 属性Set和Get方法要一个专门的属性。这里设置为Public。
  240. var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
  241. // 添加属性到myTypeBuilder。
  242. foreach (CustPropertyInfo cpi in lcpi)
  243. {
  244. //定义字段。
  245. FieldBuilder customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName, cpi.Type, FieldAttributes.Private);
  246. //customerNameBldr.SetConstant("11111111");
  247. //定义属性。
  248. //最后一个参数为null,因为属性没有参数。
  249. var custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName, PropertyAttributes.HasDefault, cpi.Type, null);
  250. //custNamePropBldr.SetConstant("111111111");
  251. //定义Get方法。
  252. var custNameGetPropMthdBldr = myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName, getSetAttr, cpi.Type, Type.EmptyTypes);
  253. var custNameGetIL = custNameGetPropMthdBldr.GetILGenerator();
  254. try
  255. {
  256. custNameGetIL.Emit(OpCodes.Ldarg_0);
  257. //custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
  258. custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
  259. custNameGetIL.Emit(OpCodes.Ret);
  260. }
  261. catch (Exception)
  262. {
  263. // ignored
  264. }
  265. //定义Set方法。
  266. var custNameSetPropMthdBldr = myTypeBuilder.DefineMethod(cpi.SetPropertyMethodName, getSetAttr, null, new[]
  267. {
  268. cpi.Type
  269. });
  270. var custNameSetIL = custNameSetPropMthdBldr.GetILGenerator();
  271. custNameSetIL.Emit(OpCodes.Ldarg_0);
  272. custNameSetIL.Emit(OpCodes.Ldarg_1);
  273. custNameSetIL.Emit(OpCodes.Stfld, customerNameBldr);
  274. custNameSetIL.Emit(OpCodes.Ret);
  275. //custNamePropBldr.SetConstant("ceshi");
  276. //把创建的两个方法(Get,Set)加入到PropertyBuilder中。
  277. custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr);
  278. custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr);
  279. }
  280. }
  281. /// <summary>
  282. /// 把属性加入到类型的实例。
  283. /// </summary>
  284. /// <param name="classType">类型的实例。</param>
  285. /// <param name="lcpi">要加入的属性列表。</param>
  286. /// <returns>返回处理过的类型的实例。</returns>
  287. public static Type AddPropertyToType(this Type classType, List<CustPropertyInfo> lcpi)
  288. {
  289. AssemblyName myAsmName = new AssemblyName
  290. {
  291. Name = "MyDynamicAssembly"
  292. };
  293. //创建一个程序集,设置为AssemblyBuilderAccess.RunAndCollect。
  294. AssemblyBuilder myAsmBuilder = AssemblyBuilder.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndCollect);
  295. //创建一个单模程序块。
  296. ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name);
  297. //创建TypeBuilder。
  298. // ReSharper disable once AssignNullToNotNullAttribute
  299. TypeBuilder myTypeBuilder = myModBuilder.DefineType(classType.FullName, TypeAttributes.Public);
  300. //把lcpi中定义的属性加入到TypeBuilder。将清空其它的成员。其功能有待扩展,使其不影响其它成员。
  301. AddPropertyToTypeBuilder(myTypeBuilder, lcpi);
  302. //创建类型。
  303. Type retval = myTypeBuilder.CreateType();
  304. //保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。
  305. //myAsmBuilder.Save(myAsmName.Name + ".dll");
  306. return retval;
  307. }
  308. #endregion
  309. #region 辅助类
  310. /// <summary>
  311. /// 自定义的属性信息类型。
  312. /// </summary>
  313. public class CustPropertyInfo
  314. {
  315. /// <summary>
  316. /// 空构造。
  317. /// </summary>
  318. public CustPropertyInfo()
  319. {
  320. }
  321. /// <summary>
  322. /// 根据属性类型名称,属性名称构造实例。
  323. /// </summary>
  324. /// <param name="type">属性类型名称。</param>
  325. /// <param name="propertyName">属性名称。</param>
  326. public CustPropertyInfo(Type type, string propertyName)
  327. {
  328. Type = type;
  329. PropertyName = propertyName;
  330. }
  331. public CustPropertyInfo(Type type, string propertyName, object propertyValue) : this(type, propertyName)
  332. {
  333. PropertyValue = propertyValue;
  334. }
  335. /// <summary>
  336. /// 获取或设置属性类型名称。
  337. /// </summary>
  338. public Type Type { get; set; }
  339. /// <summary>
  340. /// 获取或设置属性名称。
  341. /// </summary>
  342. public string PropertyName { get; set; }
  343. /// <summary>
  344. /// 属性值
  345. /// </summary>
  346. public object PropertyValue { get; set; }
  347. /// <summary>
  348. /// 获取属性字段名称。
  349. /// </summary>
  350. public string FieldName
  351. {
  352. get
  353. {
  354. if (PropertyName.Length < 1)
  355. {
  356. return "";
  357. }
  358. return PropertyName.Substring(0, 1).ToLower() + PropertyName.Substring(1);
  359. }
  360. }
  361. /// <summary>
  362. /// 获取属性在IL中的Set方法名。
  363. /// </summary>
  364. public string SetPropertyMethodName => "set_" + PropertyName;
  365. /// <summary>
  366. /// 获取属性在IL中的Get方法名。
  367. /// </summary>
  368. public string GetPropertyMethodName => "get_" + PropertyName;
  369. }
  370. #endregion
  371. }
  372. }