C# 反射结构体struct的一个坑
今天代码用到了反射赋值,代码是这样写的:
1 var objtype = obj.GetType(); 2 var Fieldinfo = objtype.GetField("I64"); 3 Fieldinfo.SetValue(obj, 100L);
当用户传进来的obj是class的时候无问题.但是传进来struct的时候,即不报错也不提示,但却什么值都没赋上!
经过多番查询.直到看到这个关于struct和class的区别:
http://www.cnblogs.com/gsk99/archive/2011/05/20/1904552.html
和这个装箱/拆箱的说明:
http://www.cnblogs.com/huashanlin/archive/2007/05/16/749359.html
其中有一段:
6:装箱/拆箱的内部操作。
装箱:
对值类型在堆中分配一个对象实例,并将该值复制到新的对象中。按三步进行。
第一步:新分配托管堆内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)。
第二步:将值类型的实例字段拷贝到新分配的内存中。
第三步:返回托管堆中新分配对象的地址。这个地址就是一个指向对象的引用了。
有人这样理解:如果将Int32装箱,返回的地址,指向的就是一个Int32。我认为也不是不能这样理解,但这确实又有问题,一来它不全面,二来指向Int32并没说出它的实质(在托管堆中)。
拆箱:
检查对象实例,确保它是给定值类型的一个装箱值。将该值从实例复制到值类型变量中。
有书上讲,拆箱只是获取引用对象中指向值类型部分的指针,而内容拷贝则是赋值语句之触发。我觉得这并不要紧。最关键的是检查对象实例的本质,拆箱和装箱的类型必需匹配,这一点上,在IL层上,看不出原理何在,我的猜测,或许是调用了类似GetType之类的方法来取出类型进行匹配(因为需要严格匹配)。
我看了看我调用的:SetValue方法.第一个参数是个object,是引用类型,也就是说,当我调用的时候,其实net把我的struct复制了一份,然后在新的那份改了值,我这边这份当然是没有被动过的.
原因找到了,解决也就不难了,解决方案1:
在调用SetValue之前,就把我的struct转成object,然后调用完再转回来:
1 public struct MyStruct 2 { 3 public int TestInt; 4 } 5 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 var Mystruct = new MyStruct(); 11 Type myType = typeof(MyStruct); 12 FieldInfo myFieldInfo = myType.GetField("TestInt"); 13 Object someBoxedStruct = Mystruct; 14 myFieldInfo.SetValue(someBoxedStruct, 1); 15 MyStruct someUnBoxedStruct = (MyStruct)someBoxedStruct; 16 } 17 }
尝试了一下,是可以的.
还有一种方法,偶然搜索到的,把写入那部分改成这样:
1 FieldInfo fi = typeof(T).GetField(name, BindingFlags.Public | BindingFlags.Instance); 2 TypedReference reference = __makeref(obj); 3 fi.SetValueDirect(reference, x);
也是可以的.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?