使用反射时如何处理含私有泛型类型的对象?
优化反射操作私有字典字段的方案
方案1:利用非泛型IDictionary接口直接操作
Dictionary<TKey, TValue>实现了非泛型的IDictionary接口,你可以直接将获取到的object实例强转为IDictionary,无需反射就能完成字典的基础操作:
// 假设已通过反射拿到m_voiceHudPools字段的object实例 IDictionary voiceHudPools = (IDictionary)yourFieldValue; // 遍历键值对 foreach (DictionaryEntry entry in voiceHudPools) { string key = (string)entry.Key; object value = entry.Value; // 以object类型持有SourceVoicePool实例 // 若需调用value的方法仍需反射,但字典自身操作无需反射 } // 添加元素(若原字典允许修改) voiceHudPools.Add("newKey", yourSourceVoicePoolInstance); // 查找元素 if (voiceHudPools.Contains("targetKey")) { object targetValue = voiceHudPools["targetKey"]; }
方案2:用dynamic类型简化调用
C#的dynamic类型可以在运行时解析方法调用,省去大量手动反射代码:
dynamic voiceHudPools = yourFieldValue; // 直接调用字典方法 foreach (var entry in voiceHudPools) { string key = entry.Key; dynamic value = entry.Value; // 也可改用object类型,按需选择 // 调用value的私有方法仍需反射,但字典操作可直接编写 } // 添加或修改元素 voiceHudPools["newKey"] = yourSourceVoicePoolInstance; // 获取元素 dynamic targetValue = voiceHudPools["targetKey"];
注意:dynamic会带来少量运行时开销,但代码简洁度远高于手动反射。
方案3:反射生成Dictionary<string, object>副本
如果确实需要Dictionary<string, object>类型,可以通过反射调用泛型转换方法生成副本:
// 定义泛型转换方法 public static Dictionary<string, object> ConvertDict<TValue>(IDictionary<string, TValue> dict) { return dict.ToDictionary(kv => kv.Key, kv => (object)kv.Value); } // 通过反射调用该方法 MethodInfo convertMethod = typeof(YourClass).GetMethod("ConvertDict", BindingFlags.Static | BindingFlags.Public); MethodInfo genericMethod = convertMethod.MakeGenericMethod(yourFieldValue.GetType().GetGenericArguments()[1]); Dictionary<string, object> resultDict = (Dictionary<string, object>)genericMethod.Invoke(null, new object[] { yourFieldValue });
注意:这是原字典的副本,原字典的修改不会同步到副本中,若需操作原字典,优先选择前两种方案。
方案4:表达式树生成高性能访问器(高频场景首选)
如果该操作需要频繁执行,表达式树能生成编译后的委托,性能接近直接访问字段:
// 获取目标字段的FieldInfo FieldInfo fieldInfo = typeof(TargetClass).GetField("m_voiceHudPools", BindingFlags.NonPublic | BindingFlags.Instance); // 生成获取字段的表达式并编译为委托 ParameterExpression instanceParam = Expression.Parameter(typeof(TargetClass), "instance"); MemberExpression fieldAccess = Expression.Field(instanceParam, fieldInfo); UnaryExpression convertToIDict = Expression.Convert(fieldAccess, typeof(IDictionary)); Func<TargetClass, IDictionary> getDict = Expression.Lambda<Func<TargetClass, IDictionary>>(convertToIDict, instanceParam).Compile(); // 后续直接调用委托获取字典 IDictionary voiceHudPools = getDict(targetInstance); // 再用IDictionary接口操作,同方案1
第一次编译表达式会有轻微开销,后续调用性能与直接访问字段几乎一致。
内容的提问来源于stack exchange,提问作者K.H.
相关产品推荐
相关产品推荐

