• .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         }

    运行结果如下:

  • 相关阅读:
    git rebase命令
    java中HashSet对象内的元素的hashCode值不能变化
    Spring中WebApplicationInitializer的理解
    mysql判断表字段或索引是否存在,然后修改
    mysql存储过程
    判断地图上的点是否在圆形,多边形,区域内
    计算任意多边形的面积、中心、重心
    判断点是否在任意多边形内
    springMvc将对象json返回时自动忽略掉对象中的特定属性的注解方式
    String.format()详细用法
  • 原文地址:https://www.cnblogs.com/jkswjw/p/3252602.html
Copyright © 2020-2023  润新知