如何通过反射递归实例化类中的所有嵌套类?
如何通过反射递归实例化类中的所有嵌套类(不修改原类代码)
我需要通过反射自动且递归地实例化某个类中的所有嵌套类,不能修改原类的内部代码,只能从外部处理。我的目标是让这些嵌套类的实例能被序列化器识别,否则序列化器会忽略嵌套类中的常量,只发送外层类的内容。
我已经能通过反射枚举嵌套类型并创建实例,但不知道如何将这些实例附加到外层的容器对象上。
示例模板代码
void someCode() { Nest MyNest = new Nest(); createInstancesOfAllClassesInside(MyNest); } void createInstancesOfAllClassesInside(object anyObj) { // 如何用反射实现? } public class Nest { public class A { public class A1 { public class A2 { public string x = "Activate me!"; } } } public class B { public class B1 { } } public string s = "Hello"; }
补充说明:这里的“激活”就是指用new()实例化嵌套类。
我的非工作尝试
以下是我目前的尝试,但无法实现将实例附加到容器对象的功能:
public void CreateInstancesOfAllClassesInside(object obj) { var objType = obj.GetType(); // 遍历对象类型的所有嵌套类型 foreach (Type nestedType in objType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)) { // 创建嵌套类型的实例 var instance = Activator.CreateInstance(nestedType); // 找不到类似SetValue(obj, instance)的方法将实例附加到容器! // 递归实例化该实例内部的嵌套类 CreateInstancesOfAllClassesInside(instance); } } public void CreateInstancesOfAllClassesInside2(ref object obj) { var objType = obj.GetType(); // 遍历对象类型的所有嵌套类型 foreach (Type nestedType in objType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)) { // 创建嵌套类型的实例 var instance = Activator.CreateInstance(nestedType); // 递归实例化该实例内部的嵌套类 CreateInstancesOfAllClassesInside2(ref instance); // 调用构造函数确保初始化 ConstructorInfo[] ctors = nestedType.GetConstructors(); if (ctors.Length > 0) { ctors[0].Invoke(instance, (object[])null); } // 嵌套类的实例没有出现在根对象中! } }
实际需要处理的类示例
比如下面这个类,实例化_CONST时,内部的FOLDERS_APP、POSTS等嵌套类不会被实例化,导致序列化器忽略其中的常量:
public class _CONST { public class FOLDERS_APP { public class POSTS { public const string FOLDER_POSTS_USERS = "somefolder1/"; public const string FOLDER_PRO_POSTS_FROM_USERS = "somefolder2/"; public const string FOLDER_FOR_IM_IN_POST = "somefolder3/"; public const string FOLDER_ATTACH_TO_POSTS = "somefolder4/"; } public class MANIFESTOS { public const string FOLDER_APPLICATION_MO = "somefolder5/"; public const string FOLDER_FOM_S = "somefolder6/"; } } }
解决方案
核心问题在于:原类中并没有定义存储嵌套类实例的字段或属性,所以直接创建嵌套类实例后无法直接附加到原对象上。针对这个问题,有两种可行的处理方式:
方式1:使用ExpandoObject包装原对象(推荐用于序列化场景)
将原对象的成员和嵌套类实例都存入ExpandoObject,这样序列化器可以识别动态添加的嵌套类实例:
public static ExpandoObject WrapWithNestedInstances(object obj) { var expando = new ExpandoObject() as IDictionary<string, object>; // 复制原对象的所有公共字段和属性到ExpandoObject var objType = obj.GetType(); foreach (var field in objType.GetFields(BindingFlags.Public | BindingFlags.Instance)) { expando[field.Name] = field.GetValue(obj); } foreach (var prop in objType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (prop.CanRead) { expando[prop.Name] = prop.GetValue(obj); } } // 递归处理嵌套类型 foreach (var nestedType in objType.GetNestedTypes(BindingFlags.Public)) { // 创建嵌套类实例 var nestedInstance = Activator.CreateInstance(nestedType); // 递归包装嵌套实例的内部嵌套类 var wrappedNested = WrapWithNestedInstances(nestedInstance); // 将包装后的嵌套实例添加到ExpandoObject中,使用嵌套类的名称作为键 expando[nestedType.Name] = wrappedNested; } return (ExpandoObject)expando; }
使用方式:
void someCode() { _CONST constObj = new _CONST(); var wrappedObj = WrapWithNestedInstances(constObj); // 对wrappedObj进行序列化即可包含所有嵌套类的实例和常量 }
方式2:动态生成派生类并添加嵌套类属性(适合需要强类型的场景)
如果需要强类型的对象,可以通过反射动态生成原类的派生类,自动添加嵌套类的实例属性,再创建该派生类的实例:
using System.Reflection.Emit; public static object CreateInstanceWithNestedInstances(Type targetType) { // 动态生成派生类 var assemblyName = new AssemblyName("DynamicNestedInstances"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicNestedInstancesModule"); var typeBuilder = moduleBuilder.DefineType(targetType.Name + "WithNested", TypeAttributes.Public | TypeAttributes.Class, targetType); // 为每个嵌套类型添加自动实例化的属性 foreach (var nestedType in targetType.GetNestedTypes(BindingFlags.Public)) { // 定义私有字段存储嵌套实例 var fieldBuilder = typeBuilder.DefineField($"_{nestedType.Name}", nestedType, FieldAttributes.Private); // 定义公共属性 var propBuilder = typeBuilder.DefineProperty(nestedType.Name, PropertyAttributes.None, nestedType, null); // 属性get方法:如果字段未实例化则创建实例并递归处理 var getMethodBuilder = typeBuilder.DefineMethod($"get_{nestedType.Name}", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, nestedType, Type.EmptyTypes); var getIl = getMethodBuilder.GetILGenerator(); getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Ldfld, fieldBuilder); var label = getIl.DefineLabel(); getIl.Emit(OpCodes.Brtrue_S, label); // 创建嵌套实例 getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Newobj, nestedType.GetConstructor(Type.EmptyTypes)); // 递归处理嵌套实例的内部嵌套类 getIl.Emit(OpCodes.Call, typeof(YourClassName).GetMethod("CreateInstanceWithNestedInstances", BindingFlags.Public | BindingFlags.Static)); getIl.Emit(OpCodes.Stfld, fieldBuilder); getIl.MarkLabel(label); getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Ldfld, fieldBuilder); getIl.Emit(OpCodes.Ret); propBuilder.SetGetMethod(getMethodBuilder); } // 创建动态类型的实例 var dynamicType = typeBuilder.CreateType(); return Activator.CreateInstance(dynamicType); }
使用方式:
void someCode() { var constObj = CreateInstanceWithNestedInstances(typeof(_CONST)); // constObj包含所有嵌套类的属性,序列化时会包含其中的常量 }
内容的提问来源于stack exchange,提问作者Jada
相关产品推荐
相关产品推荐

