随笔 - 11  文章 - 0  评论 - 28  阅读 - 18043

.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         }
复制代码

运行结果如下:

 

 

 

 

posted on   梦回西夏  阅读(1489)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示