.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 }
运行结果如下: