C# ClassHelper動態建立程式集和類, 新增/刪除類屬性
阿新 • • 發佈:2020-04-22
using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Threading; namespace DynamicTest { /// <summary> /// 類幫助器,可以動態對類,類成員進行控制(新增,刪除),目前只支援屬性控制。 /// 注意,屬性以外的其它成員會被清空,功能還有待完善,使其不影響其它成員。 /// </summary> public class ClassHelper { #region 公有方法 /// <summary> /// 防止例項化。 /// </summary> private ClassHelper() { } /// <summary> /// 根據類的型別建立類例項。 /// </summary> /// <param name="t">將要建立的型別。</param> /// <returns>返回建立的類例項。</returns> public static object CreateInstance(Type t) { return Activator.CreateInstance(t); } /// <summary> /// 根據類的名稱,屬性列表建立型例項。 /// </summary> /// <param name="className">將要建立的類的名稱。</param> /// <param name="lcpi">將要建立的類的屬性列表。</param> /// <returns>返回建立的類例項</returns> public static object CreateInstance(string className,List<CustPropertyInfo> lcpi) { Type t = BuildType(className); t = AddProperty(t,lcpi); return Activator.CreateInstance(t); } /// <summary> /// 根據屬性列表建立類的例項,預設類名為DefaultClass,由於生成的類不是強型別,所以類名可以忽略。 /// </summary> /// <param name="lcpi">將要建立的類的屬性列表</param> /// <returns>返回建立的類的例項。</returns> public static object CreateInstance(List<CustPropertyInfo> lcpi) { return CreateInstance("DefaultClass",lcpi); } /// <summary> /// 根據類的例項設定類的屬性。 /// </summary> /// <param name="classInstance">將要設定的類的例項。</param> /// <param name="propertyName">將要設定屬性名。</param> /// <param name="propertSetValue">將要設定屬性值。</param> public static void SetPropertyValue(object classInstance,string propertyName,object propertSetValue) { classInstance.GetType().InvokeMember(propertyName,BindingFlags.SetProperty,null,classInstance,new object[] { Convert.ChangeType(propertSetValue,propertSetValue.GetType()) }); } /// <summary> /// 根據類的例項獲取類的屬性。 /// </summary> /// <param name="classInstance">將要獲取的類的例項</param> /// <param name="propertyName">將要設定的屬性名。</param> /// <returns>返回獲取的類的屬性。</returns> public static object GetPropertyValue(object classInstance,string propertyName) { return classInstance.GetType().InvokeMember(propertyName,BindingFlags.GetProperty,new object[] { }); } /// <summary> /// 建立一個沒有成員的型別的例項,類名為"DefaultClass"。 /// </summary> /// <returns>返回建立的型別的例項。</returns> public static Type BuildType() { return BuildType("DefaultClass"); } /// <summary> /// 根據類名建立一個沒有成員的型別的例項。 /// </summary> /// <param name="className">將要建立的型別的例項的類名。</param> /// <returns>返回建立的型別的例項。</returns> public static Type BuildType(string className) { AppDomain myDomain = Thread.GetDomain(); AssemblyName myAsmName = new AssemblyName(); myAsmName.Name = "MyDynamicAssembly"; //建立一個永久程式集,設定為AssemblyBuilderAccess.RunAndSave。 AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,AssemblyBuilderAccess.RunAndSave); //建立一個永久單模程式塊。 ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name,myAsmName.Name + ".dll"); //建立TypeBuilder。 TypeBuilder myTypeBuilder = myModBuilder.DefineType(className,TypeAttributes.Public); //建立型別。 Type retval = myTypeBuilder.CreateType(); //儲存程式集,以便可以被Ildasm.exe解析,或被測試程式引用。 //myAsmBuilder.Save(myAsmName.Name + ".dll"); return retval; } /// <summary> /// 新增屬性到型別的例項,注意:該操作會將其它成員清除掉,其功能有待完善。 /// </summary> /// <param name="classType">指定型別的例項。</param> /// <param name="lcpi">表示屬性的一個列表。</param> /// <returns>返回處理過的型別的例項。</returns> public static Type AddProperty(Type classType,List<CustPropertyInfo> lcpi) { //合併先前的屬性,以便一起在下一步進行處理。 MergeProperty(classType,lcpi); //把屬性加入到Type。 return AddPropertyToType(classType,lcpi); } /// <summary> /// 新增屬性到型別的例項,其功能有待完善。 /// </summary> /// <param name="classType">指定型別的例項。</param> /// <param name="cpi">表示一個屬性。</param> /// <returns>返回處理過的型別的例項。</returns> public static Type AddProperty(Type classType,CustPropertyInfo cpi) { List<CustPropertyInfo> lcpi = new List<CustPropertyInfo>(); lcpi.Add(cpi); //合併先前的屬性,lcpi); } /// <summary> /// 從型別的例項中移除屬性,其功能有待完善。 /// </summary> /// <param name="classType">指定型別的例項。</param> /// <param name="propertyName">要移除的屬性。</param> /// <returns>返回處理過的型別的例項。</returns> public static Type DeleteProperty(Type classType,string propertyName) { List<string> ls = new List<string>(); ls.Add(propertyName); //合併先前的屬性,以便一起在下一步進行處理。 List<CustPropertyInfo> lcpi = SeparateProperty(classType,ls); //把屬性加入到Type。 return AddPropertyToType(classType,其功能有待完善。 /// </summary> /// <param name="classType">指定型別的例項。</param> /// <param name="ls">要移除的屬性列表。</param> /// <returns>返回處理過的型別的例項。</returns> public static Type DeleteProperty(Type classType,List<string> ls) { //合併先前的屬性,lcpi); } #endregion #region 私有方法 /// <summary> /// 把型別的例項t和lcpi引數裡的屬性進行合併。 /// </summary> /// <param name="t">例項t</param> /// <param name="lcpi">裡面包含屬性列表的資訊。</param> private static void MergeProperty(Type t,List<CustPropertyInfo> lcpi) { foreach (PropertyInfo pi in t.GetProperties()) { CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType.FullName,pi.Name); lcpi.Add(cpi); } } /// <summary> /// 從型別的例項t的屬性移除屬性列表lcpi,返回的新屬性列表在lcpi中。 /// </summary> /// <param name="t">型別的例項t。</param> /// <param name="ls">要移除的屬性列表。</param> private static List<CustPropertyInfo> SeparateProperty(Type t,List<string> ls) { List<CustPropertyInfo> ret = new List<CustPropertyInfo>(); foreach (PropertyInfo pi in t.GetProperties()) { foreach (string s in ls) { if (pi.Name != s) { CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType.FullName,pi.Name); ret.Add(cpi); } } } return ret; } /// <summary> /// 把lcpi引數裡的屬性加入到myTypeBuilder中。注意:該操作會將其它成員清除掉,其功能有待完善。 /// </summary> /// <param name="myTypeBuilder">型別構造器的例項。</param> /// <param name="lcpi">裡面包含屬性列表的資訊。</param> private static void AddPropertyToTypeBuilder(TypeBuilder myTypeBuilder,List<CustPropertyInfo> lcpi) { PropertyBuilder custNamePropBldr; MethodBuilder custNameGetPropMthdBldr; MethodBuilder custNameSetPropMthdBldr; MethodAttributes getSetAttr; ILGenerator custNameGetIL; ILGenerator custNameSetIL; // 屬性Set和Get方法要一個專門的屬性。這裡設定為Public。 getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; // 新增屬性到myTypeBuilder。 foreach (CustPropertyInfo cpi in lcpi) { //定義欄位。 FieldBuilder customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName,Type.GetType(cpi.Type),FieldAttributes.Private); customerNameBldr.SetConstant("11111111"); //定義屬性。 //最後一個引數為null,因為屬性沒有引數。 custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName,PropertyAttributes.HasDefault,null); custNamePropBldr.SetConstant("111111111"); //定義Get方法。 custNameGetPropMthdBldr = myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName,getSetAttr,Type.EmptyTypes); custNameGetIL = custNameGetPropMthdBldr.GetILGenerator(); try { custNameGetIL.Emit(OpCodes.Ldarg_0); //custNameGetIL.Emit(OpCodes.Ldfld,customerNameBldr); custNameGetIL.Emit(OpCodes.Ldfld,customerNameBldr); custNameGetIL.Emit(OpCodes.Ret); } catch (Exception ex) { Console.WriteLine(ex.Message); } //定義Set方法。 custNameSetPropMthdBldr = myTypeBuilder.DefineMethod(cpi.SetPropertyMethodName,new Type[] { Type.GetType(cpi.Type) }); custNameSetIL = custNameSetPropMthdBldr.GetILGenerator(); custNameSetIL.Emit(OpCodes.Ldarg_0); custNameSetIL.Emit(OpCodes.Ldarg_1); custNameSetIL.Emit(OpCodes.Stfld,customerNameBldr); custNameSetIL.Emit(OpCodes.Ret); //custNamePropBldr.SetConstant("ceshi"); //把建立的兩個方法(Get,Set)加入到PropertyBuilder中。 custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr); custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr); } } /// <summary> /// 把屬性加入到型別的例項。 /// </summary> /// <param name="classType">型別的例項。</param> /// <param name="lcpi">要加入的屬性列表。</param> /// <returns>返回處理過的型別的例項。</returns> public static Type AddPropertyToType(Type classType,List<CustPropertyInfo> lcpi) { AppDomain myDomain = Thread.GetDomain(); AssemblyName myAsmName = new AssemblyName(); myAsmName.Name = "MyDynamicAssembly"; //建立一個永久程式集,myAsmName.Name + ".dll"); //建立TypeBuilder。 TypeBuilder myTypeBuilder = myModBuilder.DefineType(classType.FullName,TypeAttributes.Public); //把lcpi中定義的屬性加入到TypeBuilder。將清空其它的成員。其功能有待擴充套件,使其不影響其它成員。 AddPropertyToTypeBuilder(myTypeBuilder,lcpi); //建立型別。 Type retval = myTypeBuilder.CreateType(); //儲存程式集,或被測試程式引用。 //myAsmBuilder.Save(myAsmName.Name + ".dll"); return retval; } #endregion #region 輔助類 /// <summary> /// 自定義的屬性資訊型別。 /// </summary> public class CustPropertyInfo { private string propertyName; private string type; /// <summary> /// 空構造。 /// </summary> public CustPropertyInfo() { } /// <summary> /// 根據屬性型別名稱,屬性名稱構造例項。 /// </summary> /// <param name="type">屬性型別名稱。</param> /// <param name="propertyName">屬性名稱。</param> public CustPropertyInfo(string type,string propertyName) { this.type = type; this.propertyName = propertyName; } /// <summary> /// 獲取或設定屬性型別名稱。 /// </summary> public string Type { get { return type; } set { type = value; } } /// <summary> /// 獲取或設定屬性名稱。 /// </summary> public string PropertyName { get { return propertyName; } set { propertyName = value; } } /// <summary> /// 獲取屬性欄位名稱。 /// </summary> public string FieldName { get { if (propertyName.Length < 1) return ""; return propertyName.Substring(0,1).ToLower() + propertyName.Substring(1); } } /// <summary> /// 獲取屬性在IL中的Set方法名。 /// </summary> public string SetPropertyMethodName { get { return "set_" + PropertyName; } } /// <summary> /// 獲取屬性在IL中的Get方法名。 /// </summary> public string GetPropertyMethodName { get { return "get_" + PropertyName; } } } #endregion } }