zoukankan      html  css  js  c++  java
  • C# 动态添加属性 非原创 有修改

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

    非原创,亲测可用,但是添加到类型目前测试的结果看来,不能添加String和Guid,目前只有添加Int32成功了

    其他人的更详细的

    http://blog.csdn.net/bai_bzl/article/details/1920409

  • 相关阅读:
    ios -为什么用WKWebView加载相同的html文本,有时展示的内容却不一样。
    weex
    [Objective-C 面试简要笔记]
    [iOS 基于CoreBluetooth的蓝牙4.0通讯]
    [SVN Mac自带SVN结合新浪SAE进行代码管理]
    [SVN Mac的SVN使用]
    [iOS dispatch_once创建单例]
    [iOS UI设计笔记整理汇总]
    [iOS 视频流开发-获得视频帧处理]
    [iOS OpenCV错误解决]
  • 原文地址:https://www.cnblogs.com/MasonRayn/p/2856356.html
Copyright © 2011-2022 走看看