C#使用反射给结构体数组成员赋值报CS0266错误如何解决
问题根因
- 错误
CS0266是因为System.Array是所有数组类型的基类,基类实例赋值给派生类变量时需要显式强转,比如(Address[])arr即可解决该编译报错 - 反射赋值不生效是因为结构体是值类型,调用
FieldInfo.SetValue时传入的结构体参数会被自动装箱为独立的object副本,修改的是副本不会更新原结构体,所以出现赋值后数组还是null的情况
修复方案
本地测试代码修复
将结构体先装箱为同一个object对象操作,修改完成后再拆箱回原变量即可:
struct Person { public Address[] addresses; } struct Address { public int nCode; public string homeAddress; } class Program { static void Main(string[] args) { Person p = new Person(); int nSize = 100; var fields = typeof(Person).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); // 先将值类型装箱,操作同一个引用对象 object boxedP = p; foreach (var fieldInfo in fields) { if (fieldInfo.FieldType.IsArray) { Array arr = Array.CreateInstance(fieldInfo.FieldType.GetElementType(), nSize); // 给装箱后的对象赋值 fieldInfo.SetValue(boxedP, arr); // 把修改后的结果写回原结构体 p = (Person)boxedP; if(p.addresses == null) { Console.WriteLine("Reflection-Not success"); } else { Console.WriteLine("Reflection-success"); } } } } }
通用泛型方法实现
你最初的initArray方法可以修改为以下版本,适配所有结构体类型:
using System.Reflection; using System.IO; private static void InitArray<T>(ref T item, BinaryReader br) where T : struct { var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // 装箱得到可修改的引用对象 object boxedItem = item; foreach (var arrayFieldInfo in fields) { if (!arrayFieldInfo.FieldType.IsArray) { continue; } // 从流中读取数组长度 int length = br.ReadInt32(); // 创建对应类型的数组实例 Array arr = Array.CreateInstance(arrayFieldInfo.FieldType.GetElementType(), length); // 赋值给装箱后的结构体 arrayFieldInfo.SetValue(boxedItem, arr); } // 将修改后的结果写回原参数 item = (T)boxedItem; }
内容的提问来源于stack exchange,提问作者Thành Long Nguyễn
相关产品推荐
相关产品推荐

