Chinaunix首页 | 论坛 | 博客
  • 博客访问: 49389
  • 博文数量: 21
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 190
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-24 15:25
文章分类

全部博文(21)

文章存档

2013年(21)

我的朋友

分类: C#/.net

2013-07-05 12:53:13

Topic: c# - 动态的创建新 property 对象

标题: c# - Create new property object on the fly

本文是关于如何从string和其他的信息创建出类型和属性(Types and the Properties)。采取的方法是System.Emit.

this page is about creating properties from strings and other information and you use the System.Emit (which still is the Reflection system) to build the Types and the Properties that we are interested in.


假设我们要解决的问题是,我们有一个DynamicClass,它有如下的属性。

The problem is

suppose that we have a DynamicClass, and it has the following information.


点击(此处)折叠或打开

  1. public class DynamicClass
  2. {
  3.     public Type ObjectType { get; set; }
  4.     public List<string> PropertyNameList { get; set; }
  5.     public List<Type> PropertyTypeList { get; set; }
  6. }

从该类,我们想生成PropertiesInfo,生成这些PropertiesInfo的信息在PropertyNameList和其他的属性里面).

 

from this class, we 'd like get PropertiesInfo's (the properties is represented in the above code with PropertyNameList and others.)


点击(此处)折叠或打开

  1. public PropertyInfo[] GetProperties (object o)
  2. {
  3.     PropertyInfo[] properties = o.GetType().GetProperties();
  4.  
  5.     return properties;
  6. }

我们首先需要的是创建一个表示该类型的信息对象。

So we can first create a class to represent the information about a property.

点击(此处)折叠或打开

  1. public class Field
  2.     {
  3.         public string FieldName;
  4.         public Type FieldType;
  5.     }


点击(此处)折叠或打开

  1. public class Field
  2.     {
  3.         public string FieldName;
  4.         public Type FieldType;
  5.     }

我们生成了一个MyObjectBuilder类,使用Emit空间动态的创建模块,在该创建的模块中定义了属性和默认的构造器。

And we have the MyObjectBuilder class, which is to use the Emit namespace to dynamically create the modules and then use that module to define properties and default constructors.

点击(此处)折叠或打开

  1. public class MyObjectBuilder
  2.     {
  3.  
  4.         public Type objType { get; set; }
  5.  
  6.         public MyObjectBuilder()
  7.         {
  8.             this.objType = null;
  9.         }
  10.  
  11.         public object CreateNewObject(List<Field> Fields)
  12.         {
  13.             this.objType = CompileResultType(Fields);
  14.             var myObj = Activator.CreateInstance(this.objType);
  15.             return myObj;
  16.         }
  17.  
  18.         // Given MyObjectBuilder, build a List item.
  19.         public IList getObjectLsit()
  20.         {
  21.             Type listType = typeof(List<>).MakeGenericType(this.objType);
  22.             return (IList)Activator.CreateInstance(listType);
  23.         }
  24.  
  25.  
  26.         // Why do we need the CompareTo method?
  27.         public static MethodInfo GetCompareToMethod(object genericInstance, string sortExpression)
  28.         {
  29.             Type genericType = genericInstance.GetType();
  30.             object sortExpressionValue = genericType.GetProperty(sortExpression).GetValue(genericInstance, null);
  31.             Type sortExpressionType = sortExpression.GetType();
  32.             MethodInfo compareToMethodOfSortExpressionType = sortExpressionType.GetMethod("CompareTo", new Type[] { sortExpressionType });
  33.  
  34.             return compareToMethodOfSortExpressionType;
  35.         }
  36.  
  37.         // Compile the Info passed in and get a result back
  38.         public static Type CompileResultType(List<Field> Fields)
  39.         {
  40.             TypeBuilder tb = GetTypeBuilder();
  41.             // A default constructor is the void constructor
  42.             ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
  43.  
  44.             foreach (var field in Fields)
  45.             {
  46.                 CreateProperty(tb, field.FieldName, field.FieldType);
  47.             }
  48.             Type objectType = tb.CreateType();
  49.             return objectType;
  50.         }
  51.  
  52.         // Create a TypeBuilder, which should we can further to build Constructor, Properties and etc..
  53.         private static TypeBuilder GetTypeBuilder()
  54.         {
  55.             var typeSignature = "MyDynamicType";
  56.             var an = new AssemblyName(typeSignature);
  57.             AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
  58.             ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
  59.             TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
  60.                 TypeAttributes.Public
  61.                 | TypeAttributes.Class
  62.                 | TypeAttributes.AutoClass
  63.                 | TypeAttributes.AnsiClass
  64.                 | TypeAttributes.BeforeFieldInit
  65.                 | TypeAttributes.AutoLayout,
  66.                 null);
  67.             return tb;
  68.         }
  69.  
  70.         // Try to create a Property with all the necessary information passed in, such as the TypeBuilder.
  71.         //
  72.         private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
  73.         {
  74.             FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
  75.  
  76.             PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName
  77.                 , PropertyAttributes.HasDefault
  78.                 , propertyType
  79.                 , null);
  80.             MethodBuilder getPropMethodBldr = tb.DefineMethod("get_" + propertyName
  81.                 , MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
  82.                 , propertyType
  83.                 , Type.EmptyTypes);
  84.  
  85.             ILGenerator getIl = getPropMethodBldr.GetILGenerator();
  86.             getIl.Emit(OpCodes.Ldarg_0);
  87.             getIl.Emit(OpCodes.Ldfld, fieldBuilder);
  88.             getIl.Emit(OpCodes.Ret);
  89.  
  90.             MethodBuilder setPropMthBldr = tb.DefineMethod("set_" + propertyName,
  91.                     MethodAttributes.Public |
  92.                     MethodAttributes.SpecialName |
  93.                     MethodAttributes.HideBySig,
  94.                     null,
  95.                     new[] { propertyType }
  96.                     );
  97.  
  98.             ILGenerator setIl = setPropMthBldr.GetILGenerator();
  99.             Label modifyProperty = setIl.DefineLabel();
  100.             Label exitSet = setIl.DefineLabel();
  101.  
  102.             setIl.MarkLabel(modifyProperty);
  103.             setIl.Emit(OpCodes.Ldarg_0);
  104.             setIl.Emit(OpCodes.Ldarg_1);
  105.             setIl.Emit(OpCodes.Stfld, fieldBuilder); // why it is the Builder classes, rather than the actual field info?
  106.  
  107.             setIl.Emit(OpCodes.Nop);
  108.  
  109.             setIl.MarkLabel(exitSet);
  110.             setIl.Emit(OpCodes.Ret);
  111.  
  112.             propertyBuilder.SetGetMethod(getPropMethodBldr);
  113.             propertyBuilder.SetSetMethod(setPropMthBldr);
  114.         }
  115.  
  116.     }

写了如下的驱动代码。

And then we can drive the code with the following driving code.

点击(此处)折叠或打开

  1. public class MyPropertyBuilder
  2.     {
  3.         public static void SetMemberValue(MemberInfo member, object target, object value)
  4.         {
  5.             switch (member.MemberType)
  6.             {
  7.                 case MemberTypes.Field:
  8.                     ((FieldInfo)member).SetValue(target, value);
  9.                     break;
  10.                     ((PropertyInfo) member).SetValue(target, value, null);
  11.                     case MemberTypes.Property:
  12.                     break;
  13.                 default:
  14.                     throw new ArgumentException("MemberInfo must be type FieldInfo or PropertyInfo");
  15.             }
  16.         }
  17.  
  18.         public void BuildProperties()
  19.         {
  20.             // Creating a Lits of Fields (string fieldName, Type fieldType);
  21.             List<Field> Fields = new List<Field>();
  22.             Fields.Add(new Field() { FieldName = "TestName", FieldType = typeof(string)});
  23.             // MyObjectBuilder class
  24.             MyObjectBuilder o = new MyObjectBuilder();
  25.  
  26.             // creating a new object dynamically
  27.             object newObj = o.CreateNewObject(Fields);
  28.             IList objList = o.getObjectLsit();
  29.  
  30.             Type t = newObj.GetType();
  31.             object instance = Activator.CreateInstance(t);
  32.  
  33.             PropertyInfo[] props = instance.GetType().GetProperties();
  34.             int instancePropsCount = props.Count();
  35.  
  36.             for (int i = 0; i < instancePropsCount; i++)
  37.             {
  38.                 string fieldName = props[i].Name;
  39.                 MemberInfo[] mInfo = null;
  40.                 PropertyInfo pInfo = newObj.GetType().GetProperty(fieldName);
  41.  
  42.                 if (pInfo != null)
  43.                 {
  44.                     var value = pInfo.GetValue(newObj, null);
  45.                     mInfo = t.GetMember(fieldName);
  46.  
  47.                     if (value != null && mInfo != null && !string.IsNullOrEmpty(mInfo[0].ToString()))
  48.                     {
  49.                         SetMemberValue(mInfo[0], instance, value);
  50.                     }
  51.                 }
  52.                 else
  53.                 {
  54.                     mInfo = t.GetMember(fieldName);
  55.                     if (mInfo != null && !string.IsNullOrEmpty(mInfo[0].ToString()))
  56.                     {
  57.                         SetMemberValue(mInfo[0], instance, null);
  58.                     }
  59.                 }
  60.                 objList.Add(instance);
  61.             }
  62.         }
  63.  
  64.     }

主程序是

And the code that runs the program is

点击(此处)折叠或打开

  1. static void Main(string[] args)
  2.         {
  3.             MyPropertyBuilder propBuilder = new MyPropertyBuilder();
  4.            
  5.             propBuilder.BuildProperties();
  6.  
  7.  
  8.         }

运行该程序,打开模块调试窗口,你会看到如下的信息,表示一个动态的模块被创建出来了。

And if you run it, you will see the Modules have the dynamic module loaded.

 At debug, when you check the Modules that is loaded, you can check with the follownig.

 

点击(此处)折叠或打开

  1. MyDynamicType MyDynamicType No No No symbols loaded. 16 [10216] DemoPropertyBuilder.vshost.exe: Managed (v4.0.30319)

References

:

阅读(659) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~