C#中编译期未知List对应字段名时如何正确调用AddRange方法
问题原因
一共有4处错误,分别对应从获取字段到调用方法的全流程:
- 字段名生成错误:你调用
selections[0].GetType().ToString()拿到的是类型的完整限定名(包含命名空间),比如Tree类如果在Game.Logic命名空间下,返回值是Game.Logic.Tree,转小写后拼接出来的字段名是game.logic.treeselections,完全匹配不到你定义的treeSelections字段。应该改用GetType().Name只取类名部分。 - 获取AddRange方法的所属类型错误:
field是FieldInfo类型的反射对象,你调用field.GetType()拿到的是FieldInfo类本身的类型,这个类根本没有定义AddRange方法,自然返回null。正确的做法是通过field.FieldType拿到字段声明的List<Tree>类型,再从中查找AddRange方法。 - Invoke调用时传错了目标实例:AddRange是List实例的成员方法,Invoke的第一个参数需要是List对象本身,你直接传
field(FieldInfo对象),即使拿到正确的方法也会调用失败。需要先用field.GetValue(this)从当前JobManager实例中取出存储的List对象作为调用目标。 - 参数类型不兼容:你要调用的
List<Tree>.AddRange接收的参数类型是IEnumerable<Tree>,但你传入的是List<Harvestable>,二者没有隐式转换关系,直接调用会抛出参数类型不匹配的异常,需要先把输入的集合转换为对应泛型类型的可枚举集合。
修复后可运行的代码
public void OnMarkHarvestableSignal(List<Harvestable> selections) { // 改用Name属性只取类名,避免带命名空间 string fieldName = selections[0].GetType() .Name .ToLower() + "Selections"; FieldInfo field = this.GetType() .GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); if (field is null) throw new Exception($"Field {fieldName} not found"); // 取出实际存储的List实例 object targetList = field.GetValue(this); // 从List的类型中获取AddRange方法 MethodInfo addMethod = field.FieldType.GetMethod("AddRange"); // 把输入集合转换为List对应泛型的数组 Type listElementType = field.FieldType.GetGenericArguments()[0]; Array convertedElements = Array.CreateInstance(listElementType, selections.Count); selections.CopyTo((Harvestable[])convertedElements); // 调用AddRange addMethod.Invoke(targetList, new object[] { convertedElements }); }
内容的提问来源于stack exchange,提问作者TimO
相关产品推荐
相关产品推荐

