分享

C#动态添加属性

 顺溜的书架 2014-10-06

原文:http://blog.csdn.net/numensoft/article/details/5186630


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


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多