.net 反射构造你自己的“匿名”对象

由于近来项目的底层架构某些特殊需求及场景的需要要求动态build一个对象,

属性名称个类与类型都是外界动态传入的。

不多说废话,直接上我最原始的代码:

 1         public static Type GetMyType()
 2         {
 3             string[] namelist = new string[] { "UserName", "UserID" };
 4             Dictionary<string, Type> dic = new Dictionary<string, Type>();
 5             dic.Add("UserName", typeof(string));
 6             dic.Add("UserID", typeof(int));
 7 
 8             string strDynamicModuleName = "jksdynamic";
 9             string strDynamicClassName = "<>jksdynamci";
10             AppDomain currentDomain = System.AppDomain.CurrentDomain;
11             AssemblyName assemblyName = new AssemblyName();
12             assemblyName.Name = strDynamicModuleName;
13 
14             AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
15 
16             ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(strDynamicModuleName);
17 
18             TypeBuilder typeBuilder = moduleBuilder.DefineType(strDynamicClassName, TypeAttributes.Public);
19 
20             Type[] methodArgs = { typeof(string) };
21 
22             ConstructorBuilder constructorBuiler = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(string), typeof(int) });
23 
24             //            typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard);
25             //typeBuilder.d
26             //动态创建字段
27             // FieldBuilder fb = typeBuilder.DefineField(item, typeof(System.String), FieldAttributes.Private);
28             //ILGenerator ilg = constructorBuiler.GetILGenerator();//生成 Microsoft 中间语言 (MSIL) 指令
29             //ilg.Emit(OpCodes.Ldarg_0);
30             //ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
31             //ilg.Emit(OpCodes.Ldarg_0);
32             //ilg.Emit(OpCodes.Ldarg_1);
33 
34             ////ilg.Emit(OpCodes.Stfld);
35             //ilg.Emit(OpCodes.Ret);
36 
37             int index = 0;
38             ILGenerator ilg = constructorBuiler.GetILGenerator();
39             foreach (string item in dic.Keys)
40             {
41 
42                 //typeBuilder.DefineConstructor(MethodAttributes.Assembly, CallingConventions.VarArgs, new Type[] { typeof(string), typeof(int) });
43 
44                 //动态创建字段
45                 //FieldBuilder fb = typeBuilder.DefineField("_" + item, dic[item], FieldAttributes.Private); 
46 
47                 //类型的属性成员由两部分组成,一是私有字段,二是访问私有字段的属性包装器。
48                 //包装器运行时的本质与 Method 一样,即包含 Set_Method 和 Get_Method 两个方法。
49                 //动态创建字段
50                 FieldBuilder fieldBuilder = typeBuilder.DefineField(dic[item].Name + "_" + item, dic[item], FieldAttributes.Public);
51 
52                 //FieldBuilder conFieldBuilder = typeBuilder.DefineField(item.ToLower(), dic[item], FieldAttributes.Public);
53 
54 
55                 index++;
56                 ilg.Emit(OpCodes.Ldarg_0);//向MSIL流发送属性实例
57                 ilg.Emit(OpCodes.Ldarg, index);//将指定索引的参数加到堆栈上。
58                 ilg.Emit(OpCodes.Stfld, fieldBuilder);//装载字段
59 
60 
61 
62                 //ilg.Emit(OpCodes.Stfld, fieldBuilder);
63 
64                 PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(item, PropertyAttributes.None, dic[item], null);
65                 //MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
66                 MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + item, MethodAttributes.Public, dic[item], null);
67 
68                 ILGenerator ilGenerator = methodBuilder.GetILGenerator();
69                 ilGenerator.Emit(OpCodes.Ldarg_0);
70                 ilGenerator.Emit(OpCodes.Ldfld, fieldBuilder);//装载属性私有字段
71                 ilGenerator.Emit(OpCodes.Ret);
72                 propertyBuilder.SetGetMethod(methodBuilder);// 设置获取属性值的方法
73 
74                 methodBuilder = typeBuilder.DefineMethod("set_" + item,
75                                MethodAttributes.Public,
76                                typeof(void), new Type[] { dic[item] });
77 
78                 ilGenerator = methodBuilder.GetILGenerator();
79                 ilGenerator.Emit(OpCodes.Ldarg_0);
80                 ilGenerator.Emit(OpCodes.Ldarg_1);
81                 ilGenerator.Emit(OpCodes.Stfld, fieldBuilder);
82                 ilGenerator.Emit(OpCodes.Ret);
83                 propertyBuilder.SetSetMethod(methodBuilder);// 设置属性值的方法
84 
85 
86             }
87             ilg.Emit(OpCodes.Ret);
88             Type type = typeBuilder.CreateType();
89 
90             //Type typeDynamic = moduleBuilder.GetType(strDynamicClassName);
91             //object objReturn = Activator.CreateInstance(typeDynamic, "Admin", 90);
92 
93             object objReturn = Activator.CreateInstance(type, "Admin", 90);
94 
95             return type;
96 
97         }

特别说:

ldarg.0微软官网上的说明,这里不做翻译比较简单。
NOTE: ldarg.0 holds the “this” reference – ldarg.1, ldarg.2, and ldarg.3
hold the actual passed parameters. ldarg.0 is used by instance methods
to hold a reference to the current calling object instance. Static methods
do not use arg.0, since they are not instantiated and hence no reference
is needed to distinguish them.

测试代码如下:

 1         public static void TestCreateType()
 2         {
 3             Type myDynamicType = GetMyType();
 4             Console.WriteLine("Some information about my new Type '{0}':",
 5                               myDynamicType.FullName);
 6             Console.WriteLine("Assembly: '{0}'", myDynamicType.Assembly);
 7             Console.WriteLine("Attributes: '{0}'", myDynamicType.Attributes);
 8             Console.WriteLine("Module: '{0}'", myDynamicType.Module);
 9             Console.WriteLine("Members: ");
10             foreach (MemberInfo member in myDynamicType.GetMembers())
11             {
12                 Console.WriteLine("-- {0} {1};", member.MemberType, member.Name);
13             }
14             Console.WriteLine("---");
15             Type[] aPtypes = new Type[] { typeof(string), typeof(int) };
16 
17             object[] aPargs = new object[] { "JksName", 5122 };
18 
19             ConstructorInfo myDTctor = myDynamicType.GetConstructor(aPtypes);
20             Console.WriteLine("Constructor: {0};", myDTctor.ToString());
21 
22             Console.WriteLine("---");
23 
24             object amyclass = myDTctor.Invoke(aPargs);
25             Console.WriteLine("aPoint is type {0}.", amyclass.GetType());
26 
27             //Console.WriteLine("aPoint.x = {0}",
28             //                myDynamicType.InvokeMember("get_UserName",
29             //                               BindingFlags.InvokeMethod,
30             //                               null,
31             //                               myDTctor,
32             //                               new object[0]));
33             Console.WriteLine("Method ---");
34             foreach (MethodInfo method in myDynamicType.GetMethods())
35             {
36                 if (method.Name.StartsWith("get_"))
37                 {
38                     object v = method.Invoke(amyclass, null);
39                     Console.WriteLine(method.Name + " : " + v.ToString());
40                 }
41             }
42             Console.WriteLine("Property ---");
43             foreach (PropertyInfo property in myDynamicType.GetProperties())
44             {
45 
46                 Console.WriteLine(property.Name + " : " + property.GetValue(amyclass).ToString());
47 
48             }
49 
50         }

运行结果如下:

标签